1.mysql表优化和避免索引失效原则
表优化
1、单表优化
建立索引
- 根据sql的实际解析顺序建立复合索引
- 最佳左前缀,保持索引的定义和使用顺序一致
2、多表优化
连接查询
- 小表驱动大表:对于双层循环来说,外层循环(数据量)越小,内层循环(数据量)越大,程序性能越高。一般左外连接左表为驱动表,右外连接右表为驱动表,内连接选结果集小的为驱动表。
- 索引建立在经常使用的字段上,给被驱动表建立索引
- 一般我们将小表当做驱动表(指定了联接条件时,满足查询条件的记录数少表为「驱动表」,未指定联接条件时,行数少的表为「驱动表」)
3、避免索引失效原则
- 复合索引,不要跨列或无序使用(最佳左前缀),左边失效右边全部失效。但独立索引无此影响
- 复合索引,尽量使用全索引匹配
- 复合索引,不能使用不等于(!= <>)或 is null(is not null),否则自身及右侧索引全部失效。独立索引也会失效
- 复合索引,一般而言,范围查询( > < in),之后的索引会失效
- 不要在索引上进行任何操作(计算、函数、类型转换),否则索引失效
- 尽量使用索引覆盖(using index)
- like尽量以“常量”开头,不要以“%”开头,否则索引失效
- 尽量不要使用or,否则索引失效
- 强制使用索引:select * from tabname force index(index_name) where ……
- 强制不使用索引:select * from tabname ignore index(index_name) where ……
- exists和in的使用,子查询数据集大用exists,主查询数据集大用in
- 尽量不要使用 select * ……
4、order by 优化
- 双路排序,需要两次IO,先去排序字段进行排序,然后再根据主键查找selet 字段;
- 单路排序,把所有字段都读取到sort buffer里面,如果sort buffer(内存)不够大,就会使用到文件排序(磁盘),另外,也只用所有列的总长度小于max_length_for_sort_data时,才会使用单路排序,否则会自动转为双路排序。
- 尽量保证排序的一致性(都是升序或降序)
- 双路排序:
读取行指针和order by列,对他们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中读取对应的数据输出。
双路排序的开销可能会非常巨大,因为他会读取表两次,第二次读取会引发大量的随机IO,对于myisam来说,这个代价尤其昂贵,myisam表利用系统调用去提取每行的数据。 - 单路排序:
读取查询需要的所有列,按照order by 列对他们进行排序,然后扫描排序后的列表进行输出,它的效率更快一些,避免了第二次读取数据。并且把随机IO变成了顺序IO,但是它会使用更多的空间,因为它把每一行都保存在内存中了。
5、IN 和Exists的适用场景
- IN查询在内部表和外部表上都可以使用到索引;
- Exists查询仅在内部表上可以使用到索引;
- 当子查询结果集很大,而外部表较小的时候,Exists的Block Nested Loop(Block 嵌套循环)的作用开始显现,并弥补外部表无法用到索引的缺陷,查询效率会优于IN。
- 当子查询结果集较小,而外部表很大的时候,Exists的Block嵌套循环优化效果不明显,IN 的外表索引优势占主要作用,此时IN的查询效率会优于Exists。
- 网上的说法不准确,即表的规模不是看内部表和外部表,而是外部表和子查询结果集。