目录
前言
这是阅读《高性能mysql》第五章的记录。
1. 独立的列
非独立的列是索引列是表达式的一部分或是函数的参数,这会导致索引使用不当,或无法使用已有的索引
错误示例
1 | select actor_id from sakila.actor where actor_id + 1 = 5; |
1 | select ... where to_days(current_date) - to_days(date_col) <= 10; |
注意
养成简化where条件的习惯,始终将索引列单独放在比较符号的一侧
2. 前缀索引和索引选择性
索引选择性:不重复的索引值(也称为基数,cardinality)和数据表的记录总值(#T)的比值,范围从(1/#T)到1之间。索引选择性越高,查询效率越高。唯一索引的选择性是1,是最好的索引选择性,性能最好。
前缀索引:一般情况下,某个列的前缀选择性足够高,足以满足查询性能。对于BLOB\TEXT\VARCHAR类型的列,必须用前缀索引——mysql不允许索引在这些列的完整长度
诀窍:足够长——保证较高的选择性,不能太长——节约空间。前缀的“基数”应该接近于完整列的“基数”
例子:
3. 多列索引
在多列上建立独立的单列索引大部分情况下不能提高Mysql查询性能。
4. 选择合适的索引列顺序
正确的顺序依赖于使用该索引的查询,并且同时需要考虑如何更好地满足排序和分组的需要。
选择性更高的列放在索引最前列,某些场景有用。但通常不如避免随机IO和排序重要。
将选择性最高的列放在前面通常是很好,这时候索引的作用只是用于优化WHERE条件的查找。然而,性能不只是依赖于所有索引列的选择性(整体基数),也和查询条件的具体值有关,也就是和值的分布有关。可能也需要根据那些运行频率最高的查询来调整索引列的顺序,让这种情况下索引的选择性更高
5. 聚簇索引
并非一种单独的索引类型,而是一种数据存储方式。InnoDB的聚簇索引在同一个结构中保存了B-Tree索引和数据行。
6. 覆盖索引
查询只需要扫描索引而无须回表,带来的好处
- 索引条目通常远小于数据行大小,所以如果只需要读取索引,那么Mysql就会极大地减少数据访问量。这对缓存的负载非常重要,因为这种情况下响应时间大部分花在数据拷贝上。这对I/O密集型的应用也有帮助。
- 索引是按照列值顺序存储的,所以对于I/O密集型的范围查询会比随机从磁盘读取每一行数据的I/O要少得多。
- 一些存储引擎如MyISAM在内存中只缓存索引,数据则依赖于操作系统来缓存,因此访问数据需要一次系统调用,可能导致严重的性能问题。
- 对于InnoDB的聚簇索引,覆盖索引对InnoDB表特别有用。InnoDB的二级索引在叶节点中保存了行的主键值,所以如果二级主键能够覆盖查询,则可以避免对主键索引的二次查询。
7. 使用索引扫描来做排序
两种方式生成有序结果:排序操作、按索引顺序扫描(explain的type结果为index,而不是extra列的”Using index”)
扫描索引本身很快,但如果索引不能覆盖所有查询所需的全部列,就不得不每扫描一条索引记录就都回表查询一次对应的行。基本上都是随机I/O,因此按索引顺序读取数据的速度他哦农场要比顺序地全表扫描慢,尤其是在I/O密集型的工作负载时。
所以最后的结果,是同一索引既满足排序,又用于查找行。
使用索引排序的一个重要用法是当查询同时有ORDER BY 和 LIMIT 子句时
8. 压缩(前缀压缩)索引
MyISAM
9. 冗余和重复索引
重复索引——在相同的列上按照相同的顺序创建的相同类型的索引。
冗余索引——如果创建了索引(A,B),再创建索引(A)就是冗余索引,因为这只是前一个索引的前缀索引,加入是再创建(B,A)就不是。通常发生在为表添加新索引的时候。
MySQL允许在相同列创建多个索引。但需要单独维护重复的索引,并且优化器在优化查询时需要逐个考虑,这会影响性能。
大多数情况都不需要冗余索引,应该尽量扩展已有的索引而不是创建新索引。(除非扩展会让索引变得太大了)
10. 未使用的索引
建议考虑删除
定位未使用索引的工具Percona Server,MariaDB查看每个索引的使用频率。