优化总结

做索引

使用 EXPLAIN 分析,type至少要达到range级别,杜绝出现all级别

最左前缀原则

不要使用 select *

尽量用union all代替union

使用合理的分页方式以提高分页的效率, 如加索引字段作为查询条件

不建议使用%前缀模糊查询

避免在 where 子句中对字段进行 null 值判断(会导致索引失效)

当只需要一条数据的时候,使用limit 1, EXPLAIN中type列达到const类型

如果排序字段没有用到索引,就尽量少排序

如果限制条件中其他字段没有索引,尽量少用or

分段查询,使用between缩小查询访问

必要时可以使用force index来强制查询走某个索引

避免隐式类型转换

join优化,利用小表驱动大表

分库分表

做主从,读写分离

EXPLAIN

列名

描述

type

针对单表的访问方法,至少要达到range级别,杜绝出现all级别

key

实际上使用的索引,如果没有选择索引,值是NULL

ref

当使用索引列等值查询时,与索引列进行等值匹配的对象信息

rows

预估的需要读取的记录条数

Extra

额外的信息

最左前缀原则

比如设计的联合索引是 name_birthday_phone,那么我们在sql中where后面需要按照这个顺序

那最左前缀原则有什么作用呢?

充分利用索引,节省索引空间

建立了name_birthday_phone,也就意味着不需要单独再建立索引name和索引name_birthday

那为什么不按照这个顺序,索引就失效了呢?

因为B+索引是有序排序,先按照name排序再按照birthday、phone依次排序,所以突然从birthday开始查找,是无法查找的到

匹配列前缀

通常情况下一般都不太建议使用LIKE,那么该如何正确使用LIKE呢?

首先,我们需先理清楚一个字符串索引在B+树种是怎么存储?

从以上排序,得知一个字符串索引是按照字母的大小进行排序

那么程序查找自然也是需要按照这个顺序

为什么不能使用 select *

如上sql,即使是使用了索引,但是效率还是低,因为这过程发生了回表

1、 从索引 name_birthday_phone 对应的B+树中取出name值在Owater~Water之间的用户记录。此时是访问二级索引使用顺序I/O

2、 发现查询列表是 ==*==,则需到 聚集索引 中查找所有数据,这是所谓的回表。此时访问聚集索引使用随机I/O,顺序I/O比随机I/O的性能高很多。

尽量用union all代替union

union 将结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的CPU运算。

union all 则是将两个结果集进行合并,会存在重复的情况。

使用合理的分页方式以提高分页的效率

假设一张表100W条数据,如果只是单独使用limit,随着偏移量越大效率越低,因为检索需从某一个偏移量到记录集的结束所有的记录行

谨慎使用范围查询

比如between,>,

查询name的时候,会用到索引,而birthday列用不到索引,因为只有name值相同的情况下才能用,而这个查询中通过name进行范围查找的记录中可能并不是按照birthday列进行排序的。

分段查询

当扫描的行数成百万级以上的时候,可以通过程序循环遍历,分段去数据库查找数据,再将结果集进行合并,这样可以减负数据库单次执行的性能消耗。

区分in和exists

in 是先执行子查询,适合于外表大而内表小的情况。

exists 是以外层表为驱动表,先被访问,适合于外表小而内表大的情况。