前言
本文通过创建含有大量数据的数据表,测试并总结MySQL在单表、关联表、子查询、排序分组时对应的索引创建规则。
准备工作
创建表
1 | -- 创建数据表,大量数据的表 |
开启自定义函数功能
1 | -- 开启mysql二进制日志,可以做主从复制。如不开启不能自定义mysql函数 |
创建MySQL函数
1 | -- 随机产生字符串,DELIMITER $$:以$为开始结束符,代替; |
插入数据
1 | -- 执行存储过程,往dept表添加1万条数据 |
单表索引优化
索引失效规则
1 | -- 1.全值匹配我最爱 |
创建索引的建议
- 对于单键索引,尽量选择针对当前query过滤性更好的索引。
- 在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好。
- 在选择组合索引的时候,尽量选择可以能够包含当前query中的where字句中更多字段的索引。
- 在选择组合索引的时候,如果某个字段可能出现范围查询时,尽量把这个字段放在索引次序的最后面。
- 书写sql语句时,尽量避免造成索引失效的情况。
关联查询优化
- 保证被驱动表的join字段已经被索引。
- left join 时,选择小表作为驱动表,大表作为被驱动表。
- inner join 时,mysql会自己帮你把小结果集的表选为驱动表。
- 子查询尽量不要放在被驱动表,有可能使用不到索引。
- 能够直接多表关联的尽量直接关联,不用子查询。
子查询优化
尽量不要使用not in 或者 not exists,用left outer join on xxx is null 替代。
1 | EXPLAIN SELECT SQL_NO_CACHE age,count(*) FROM emp a LEFT OUTER JOIN dept b ON a.id =b.ceo WHERE b.ceo IS NULL |
排序分组优化
无过滤 不索引
如果SQL语句没有过滤条件,索引失效。1
2explain select SQL_NO_CACHE * from emp order by age,deptid;
explain select SQL_NO_CACHE * from emp order by age,deptid limit 10;顺序错,必排序
如果order by后的字段的顺序和索引创建顺序不同,Extra会出现useing filesort。1
2
3
4explain select * from emp where age=45 order by deptid,name;
explain select * from emp where age=45 order by deptid,empno;
explain select * from emp where age=45 order by name,deptid;
explain select * from emp where deptid=45 order by age;方向反 必排序
如果order by后的字段的排序方式不同,Extra会出现useing filesort。要保证排序方式全部相同。1
2explain select * from emp where age=45 order by deptid desc, name desc ;
explain select * from emp where age=45 order by deptid asc, name desc ;索引选择
当范围条件和group by 或者 order by 的字段出现二选一时 ,优先观察条件字段的过滤数量,如果过滤的数据足够多,而需要排序的数据并不多时,优先把索引放在范围字段上。反之,亦然。1
2
3SELECT SQL_NO_CACHE * FROM emp WHERE age =30 AND empno <101000 ORDER BY NAME ;
CREATE INDEX idx_age_name ON emp(age,NAME);
create index idx_age_eno on emp(age,empno);分组通排序
group by 使用索引的原则几乎跟order by一致 ,唯一区别是groupby 即使没有过滤条件用到索引,也可以直接使用索引。
覆盖索引
什么是覆盖索引?
简单说就是,select 到 from 之间查询的列 <=使用的索引列+主键