《一起学mysql》4
索引的使用 索引太少返回结果很慢,但是索引太多,又会占用空间。每次插入新记录时,索引都会针对变化重新排序 什么时候使用索引 1.where 从句中用到的字段 select * from tb where f1 = 'xx' ,如果f1 进行了索引,那么这条sql 语句的销毁就会提高 2 max(),min() select max(id) from tb 对id 索引非常有用,因为索引是按照顺序排序的,所以直接返回最后一个值即可 3.当返回的内容是索引的一部分时 这种情况不必扫描全表,只需查看索引即可 这种情况是不行的:f1 char(20),index f1(10),select f1 from tb ,因为索引只有10个字符,返回的却是20个 字符,必须扫描全表,扫描索引是不行的 4.order by select * from tb order by f1,若 f1 是被索引的,则按照索引排序的顺序返回即可 5.在连接条件处使用 select t1.c1,t1.c2,t2.c3 from t1 join t2 on t1.c4=t2.c5 where t1.c6=xx; 如果 c4 和 c5 加了索引,也可以被使用到 6.不以% 开头的like 语句vs select * from tb where name like 'jas%' name 列加了索引也会被使用到 但是这种情况是不行的:select * from tb where name like '%jas%'
因为索引是按照第一个字符的字母顺序排序的 创建索引的一些建议: 1.where 条件中的字段创建索引 2.被索引的字段内容重复率越低越好,主键是最好的索引,每个id 只返回一条记录,枚举就比较差劲,比方 说 性别,查询 性别‘男’,可能会返回近一半的记录 3.使用前缀索引 4.不要创建太多的索引,太多的索引会拖慢插入和更新速度
最左原则 这个问题单纯的口头描述很难说清楚,直接看伪代码 create table tb (f1 char(20), f2 char(20), f3 char(20), f4 char(20), index(f1,f2,f3)) 对于上面的表我们来进行下面几个sql 查询 1. select * from tb where f1='xx1' and f2 ='xx2' and f3='xx3' 2. select * from tb where f1='xx1' and f2 ='xx2' 3. select * from tb where f1='xx1' 4. select * from tb where f2 ='xx2' and f3='xx3' 5. select * from tb where f1='xx1' and f3='xx3' 上面的sql 中 1,2,3 的索引全部其作用 4中索引不会起作用 5中只有索引f1 起作用 也就是说复合索引使用的时候,必须是从最左侧开始,且是连续的,这样所有的索引才会被使用到
explain 下面来说一个很有用的东西,explain 先来建两张表,存储学生和老师信息, create table student ( stu_id int(3) zerofill, name char(10), majar char(10), teacher_id int ); create table teacher ( teacher_id int, name char(10) ); insert into student values (1,'丽丽','chemistry',1), (2,'丽娟','english',2), (3,'芳丽','儒学',3), (4,'光头强','佛学',1), (5,'熊大','math',2), (6,'熊二','地理',3), (7,'陶峰','高分子',4), (8,'波波','机电',1), (9,'米老鼠','土木',2); insert into teacher values (1,'刘老师'), (2,'王老师'), (3,'李老师'), (4,'柴老师'); 赶紧来试试explain MariaDB [jason]> explain select * from student where stu_id=1; +------+-------------+---------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | student | ALL | NULL | NULL | NULL | NULL | 9 | Using where | +------+-------------+---------+------+---------------+------+---------+------+------+-------------+ 给stu_id 加上索引再来试一下 MariaDB [jason]> alter table student add index(stu_id); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [jason]> explain select * from student where stu_id=1; +------+-------------+---------+------+---------------+--------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+------+---------------+--------+---------+-------+------+-------+ | 1 | SIMPLE | student | ref | stu_id | stu_id | 5 | const | 1 | | +------+-------------+---------+------+---------------+--------+---------+-------+------+-------+ 有木有发现不一样?下面我们来解释一下explain 各个字段含义 说实话,我对参考资料中的的解释有些困惑,我想先自己造几个例子看看 MariaDB [jason]>
show indexes from student ; +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | student | 1 |
stu_id | 1 | stu_id | A | 9 | NULL | NULL | YES | BTREE | | | | student | 1 |
teacher_id | 1 | teacher_id | A | 9 | NULL | NULL | YES | BTREE | | | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ MariaDB [jason]> drop index stu_id on student; MariaDB [jason]> alter table student add
primary key(stu_id); MariaDB [jason]> show indexes from teacher; +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | teacher | 1 | teacher_id | 1 | teacher_id | A | 1 | NULL | NULL | YES | BTREE | | | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 1 row in set (0.00 sec) MariaDB [jason]> drop index teacher_id on teacher; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [jason]> show indexes from teacher; +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | teacher | 1 | teacher_id | 1 | teacher_id | A | 1 | NULL | NULL | YES | BTREE | | | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 1 row in set (0.00 sec) MariaDB [jason]> drop index teacher_id on teacher; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [jason]> alter talbe teacher
add primary key(teacher_id); ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'talbe teacher add primary key(teacher_id)' at line 1 MariaDB [jason]> alter table teacher add primary key(teacher_id); 我们先把student表中的stu_id 和tercher表中的teacher_id 变成了主键 example1: MariaDB [jason]> explain select * from student where stu_id = 1; +------+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | student |
const | PRIMARY | PRIMARY | 4 | const | 1 | | +------+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ example2: MariaDB [jason]> explain select * from student where stu_id > 2; +------+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | student |
range | PRIMARY | PRIMARY | 4 | NULL | 7 | Using where | +------+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ example3: MariaDB [jason]> explain select * from student where teacher_id = 1; +------+-------------+---------+------+---------------+------------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+------+---------------+------------+---------+-------+------+-------+ | 1 | SIMPLE | student |
ref | teacher_id | teacher_id | 5 | const | 3 | | +------+-------------+---------+------+---------------+------------+---------+-------+------+-------+ example4: MariaDB [jason]> explain select * from student where teacher_id>2; +------+-------------+---------+-------+---------------+------------+---------+------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+-------+---------------+------------+---------+------+------+-----------------------+ | 1 | SIMPLE | student |
range | teacher_id | teacher_id | 5 | NULL | 3 | Using index condition | +------+-------------+---------+-------+---------------+------------+---------+------+------+-----------------------+ example5: ariaDB [jason]> explain select s.stu_id,s.name,s.majar,s.teacher_id,t.name -> from student s join teacher t -> on s.teacher_id = t.teacher_id; +------+-------------+-------+------+---------------+------+---------+------+------+-------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+------+---------------+------+---------+------+------+-------------------------------------------------+ | 1 | SIMPLE | t |
ALL | PRIMARY | NULL | NULL | NULL | 4 | | | 1 | SIMPLE | s |
ALL | teacher_id | NULL | NULL | NULL | 9 | Using where; Using join buffer (flat, BNL join) | +------+-------------+-------+------+---------------+------+---------+------+------+-------------------------------------------------+ example6: MariaDB [jason]> explain select s.stu_id,s.name,s.majar,s.teacher_id,t.name -> from student s left join teacher t -> on s.teacher_id = t.teacher_id; +------+-------------+-------+--------+---------------+---------+---------+--------------------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+--------+---------------+---------+---------+--------------------+------+-------+ | 1 | SIMPLE | s | ALL | NULL | NULL | NULL | NULL | 9 | | | 1 | SIMPLE | t |
eq_ref | PRIMARY | PRIMARY | 4 | jason.s.teacher_id | 1 | | +------+-------------+-------+--------+---------------+---------+---------+--------------------+------+-------+ example7: MariaDB [jason]> explain select s.stu_id,s.name,s.majar,s.teacher_id,t.name -> from student s left join teacher t -> on s.teacher_id = t.teacher_id -> where t.name is not null; +------+-------------+-------+------+---------------+------+---------+------+------+-------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+------+---------------+------+---------+------+------+-------------------------------------------------+ | 1 | SIMPLE | t | ALL | PRIMARY | NULL | NULL | NULL | 4 | Using where | | 1 | SIMPLE | s | ALL | teacher_id | NULL | NULL | NULL | 9 | Using where; Using join buffer (flat, BNL join) | +------+-------------+-------+------+---------------+------+---------+------+------+-------------------------------------------------+ example8: MariaDB [jason]> explain select s.stu_id,s.name,s.majar,s.teacher_id,t.name -> from student s right join teacher t -> on s.teacher_id = t.teacher_id; +------+-------------+-------+------+---------------+------------+---------+--------------------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+------+---------------+------------+---------+--------------------+------+-------+ | 1 | SIMPLE | t | ALL | NULL | NULL | NULL | NULL | 4 | | | 1 | SIMPLE | s
| ref | teacher_id | teacher_id | 4 | jason.t.teacher_id | 1 | | +------+-------------+-------+------+---------------+------------+---------+--------------------+------+-------+ 我尝试过使用full outer join ,但是mysql 不支持外连接 example9: MariaDB [jason]> explain select stu_id,teacher_id from student; +------+-------------+---------+-------+---------------+------------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+-------+---------------+------------+---------+------+------+-------------+ | 1 | SIMPLE | student |
index | NULL | teacher_id | 4 | NULL | 9 | Using index | +------+-------------+---------+-------+---------------+------------+---------+------+------+-------------+ example10: MariaDB [jason]> explain select max(teacher_id) from student; +------+-------------+-------+------+---------------+------+---------+------+------+------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+------+---------------+------+---------+------+------+------------------------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away | +------+-------------+-------+------+---------------+------+---------+------+------+------------------------------+ example11: MariaDB [jason]> explain select * from student order by teacher_id desc; +------+-------------+---------+------+---------------+------+---------+------+------+----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+------+---------------+------+---------+------+------+----------------+ | 1 | SIMPLE | student | ALL | NULL | NULL | NULL | NULL | 9 | Using filesort | +------+-------------+---------+------+---------------+------+---------+------+------+----------------+ example12: MariaDB [jason]> explain select * from student force index(teacher_id) order by teacher_id desc; +------+-------------+---------+-------+---------------+------------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+-------+---------------+------------+---------+------+------+-------+ | 1 | SIMPLE | student |
index | NULL | teacher_id | 4 | NULL | 9 | | +------+-------------+---------+-------+---------------+------------+---------+------+------+-------+ example13: MariaDB [jason]> alter table student add index(name); MariaDB [jason]> explain select * from student where name like '丽%'; +------+-------------+---------+-------+---------------+------+---------+------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+-------+---------------+------+---------+------+------+-----------------------+ | 1 | SIMPLE | student |
range | name | name | 41 | NULL | 2 | Using index condition | +------+-------------+---------+-------+---------------+------+---------+------+------+-----------------------+
example14: MariaDB [jason]> explain select * from student where teacher_id +5 < 7; +------+-------------+---------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | student | ALL | NULL | NULL | NULL | NULL | 9 | Using where | +------+-------------+---------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.01 sec) MariaDB [jason]> explain select * from student where teacher_id < 2; +------+-------------+---------+-------+---------------+------------+---------+------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+---------+-------+---------------+------------+---------+------+------+-----------------------+ | 1 | SIMPLE | student |
range | teacher_id | teacher_id | 4 | NULL | 3 | Using index condition | +------+-------------+---------+-------+---------------+------------+---------+------+------+-----------------------+ 1 row in set (0.00 sec) example 15: MariaDB [jason]> explain select s.stu_id,s.name,s.majar,s.teacher_id,t.name -> from student s left join teacher t -> on s.teacher_id = t.teacher_id -> where t.teacher_id is null; +------+-------------+-------+--------+---------------+---------+---------+--------------------+------+-------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+--------+---------------+---------+---------+--------------------+------+-------------------------+ | 1 | SIMPLE | s | ALL | NULL | NULL | NULL | NULL | 9 | | | 1 | SIMPLE | t | eq_ref | PRIMARY | PRIMARY | 4 | jason.s.teacher_id | 1 | Using where; Not exists | +------+-------------+-------+--------+---------------+---------+---------+--------------------+------+-------------------------+ 2 rows in set (0.00 sec) example 16: MariaDB [jason]> explain select * -> from t2 left join t1 on t2.f2=t1.f1 -> left join t3 on t3.f3=t2.f2 -> left join t4 on t4.f4=t3.f3 -> where t1.f1=1; +------+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ | 1 | SIMPLE | t2 | const | PRIMARY | PRIMARY | 4 | const | 1 | Using index | | 1 | SIMPLE | t1 | const | PRIMARY | PRIMARY | 4 | const | 1 | Using index | | 1 | SIMPLE | t3 | const | PRIMARY | PRIMARY | 4 | const | 1 | Using index | | 1 | SIMPLE | t4 | const | PRIMARY | PRIMARY | 4 | const | 1 | Using index | +------+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ 这里没有列出最左原则的例子,大家可以自己个儿试一下, 关于expalin 各列的解释可以看
这里
analyze table mysql 在执行时select 或join 时会使用索引的分布信息来决定表的关联顺序、或使用那个索引, analyze table tablename 就可以分析并存储索引的分布信息, MariaDB [jason]> analyze table student; +---------------+---------+----------+----------+ | Table | Op | Msg_type | Msg_text | +---------------+---------+----------+----------+ | jason.student | analyze | status | OK | +---------------+---------+----------+----------+ 可以通过 show index from tb_name 来查看索引的情况 MariaDB [jason]> show index from student; +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | student | 0 | PRIMARY | 1 | stu_id | A | 10 | NULL | NULL | | BTREE | | | | student | 1 | teacher_id | 1 | teacher_id | A | 10 | NULL | NULL | | BTREE | | | | student | 1 | name | 1 | name | A | 10 | NULL | NULL | YES | BTREE | | | +---------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 各字段的解释
看这里 重点解释一下Cardinality 1. 列值代表的是此列中存储的唯一值的个数(如果此列为primary key 则值为记录的行数) 2. 列值只是个估计值,并不准确。 3. 列值不会自动更新,需要通过Analyze table来更新一张表或者mysqlcheck -Aa来进行更新整个数据库。 4. 列值的大小影响Join时是否选用这个Index的判断。 5. 创建Index时,MyISAM的表Cardinality的值为null,InnoDB的表Cardinality的值大概为行数。 6. MyISAM与InnoDB对于Cardinality的计算方式不同。
optimize 如果对表进行了大量的删除和更新操作,那么表中就会留下缝隙,optimize table tb_name 可以将缝隙删除 将分割的记录连接在一起 MariaDB [jason]> optimize table student; +---------------+----------+----------+-------------------------------------------------------------------+ | Table | Op | Msg_type | Msg_text | +---------------+----------+----------+-------------------------------------------------------------------+ | jason.student | optimize | note | Table does not support optimize, doing recreate + analyze instead | | jason.student | optimize | status | OK | +---------------+----------+----------+-------------------------------------------------------------------+ 什么鬼?原来是innodb 不支持optimize, 百度找到了方法 ALTER TABLE table.name ENGINE='InnoDB'; This will create a copy of the original table, and drop the original table, and replace to the original place. Although this is safe, but I suggest you do backup and test first before doing this.
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄

更多精彩