一、单表索引优化
1.1 全值匹配
查询的条件字段按照顺序在索引中都可以匹配到
CREATE INDEX idx_age_deptid_name ON emp(age,deptid,NAME);
1.2 最佳左前缀法则
使用复合索引, 需要遵循最佳左前缀法则, 即如果索引了多列, 要遵守最左前缀法则。 指的是查询从索引的最左前列开始并且不跳过索引中的列。
过滤条件要使用索引必须按照索引建立时的顺序, 依次满足, 一旦跳过某个字段, 索引后面的字段都无法被使用。
1.3 不要在索引列上做任何计算
计算、 函数、 (自动 or 手动)类型转换,会导致索引失效而转向全表扫描。
1.4 索引列上不能有范围查询
将可能做范围查询的字段的索引顺序放在最后
1.5 尽量使用覆盖索引
即查询列和索引列一致, 不要写 select *
1.6 使用不等于(!= 或者<>)
有时会无法使用索引会导致全表扫描
1.7 字段的is not null 用不到索引 ,is null可以用到索引
当字段允许为null时:
is not null 用不到索引, is null 可以用到索引。
1.8 like 的前后模糊匹配
前缀不能出现模糊匹配否则索引失效
解决 like ‘%字符串%’时索引失效的方法:
使用覆盖索引, 既查询列和索引列一致
1.9 字符串加单引号
导致索引列上自动计算导致索引失效
1.10 减少使用 or
or可能导致索引失效尽量使用 union all 或者 union 来替代
二、关联查询优化
能够直接多表关联的尽量直接关联, 不用子查询!
小表驱动大表原则
2.1 left join
在优化关联查询时, 只有在被驱动表上建立索引才有效!
left join 时, 左侧的为驱动表, 右侧为被驱动表!
left join时, 尽量让实体表作为被驱动表。
2.2 inner join
inner join 时, mysql 会自己帮你把小结果集的表选为驱动表。
子查询尽量不要放在被驱动表, 有可能使用不到索引;
三、子查询优化
在范围判断时, 尽量不要使用 not in 和 not exists, 使用 left join on xxx is null 代替。
解决 dept 表的全表扫描, 建立 ceo 字段的索引
四、排序分组优化
4.1 无过滤不索引
无过滤, 不索引。 where, limt 都相当于一种过滤条件, 所以才能使用上索引!
using filesort 说明进行了手工排序 原因在于没有 where 作为过滤条件
4.2 顺序错, 必排序
where 两侧列的顺序可以变换, 效果相同, 但是 order by 列的顺序不能随便变换
4.3 方向反, 必排序
如果排序的字段, 顺序有差异, 就需要将差异的部分, 进行一次倒置顺序, 因此还是需要手动排序的
4.4 索引的选择
当范围条件和 group by 或者 order by 的字段出现二选一时 , 优先观察条件字段的过滤数量, 如果过滤的数据足够多, 而需要排序的数据并不多时, 优先把索引放在范围字段上。 反之, 亦然。
4.5 using filesort
mysql 的排序算法:
双路排序
MySQL 4.1 之前是使用双路排序,字面意思就是两次扫描磁盘, 最终得到数据, 读取行指针和 orderby 列, 对他
们进行排序, 然后扫描已经排序好的列表, 按照列表中的值重新从列表中读取对应的数据输出。
从磁盘取排序字段, 在 buffer 进行排序, 再从磁盘取其他字段。
简单来说, 取一批数据, 要对磁盘进行了两次扫描, 众所周知, I\O 是很耗时的, 所以在 mysql4.1 之后, 出现了第二种改进的算法, 就是单路排序。
单路排序
从磁盘读取查询需要的所有列, 按照 order by 列在 buffer 对它们进行排序, 然后扫描排序后的列表进行输出,它的效率更快一些, 避免了第二次读取数据。 并且把随机 IO 变成了顺序 IO,但是它会使用更多的空间,因为它把每一行都保存在内存中了。
优化方法:
- 增大 sort_butter_size 参数的设置
- 增大 max_length_for_sort_data 参数的设置
- 减少 select 后面的查询的字段。
4.6 使用覆盖索引
SQL 只需要通过索引就可以返回查询所需要的数据, 而不必通过二级索引查到主键之后再去查询数据
4.7 group by
group by 使用索引的原则几乎跟 order by 一致 , 唯一区别是 groupby 即使没有过滤条件用到索引, 也可以直接使用索引