mysql索引总结

索引是什么?索引是存储引擎用于快速找到记录的一种数据结构。

索引分类

B-Tree索引

MyISAM使用前缀压缩技术使得索引更小。InnoDB按照原数据存储索引。
MyISAM索引通过数据的物理位置引用被索引的行。InnoDB根据主键引用被索引的行。
可以使用B-Tree索引的查询类型:

  • 全值匹配:和索引中的所有列进行匹配
  • 匹配最左前缀:匹配第一个索引
  • 匹配列前缀:匹配某一列的值的开头部分,只使用第一个索引
  • 匹配范围值:匹配某个范围,只使用第一个索引
  • 精确匹配某一列并范围匹配另外一列
  • 只访问索引的查询
  • 排序操作:索引的有序性

哈希索引

哈希索引基于哈希表实现,只有精确匹配所有列的查询才有效。对于每一行数据,存储引擎会对所有的索引列计算一个hash值。
哈希索引的限制:

  • 哈希索引只能包含哈希值和行指针,不能使用索引的值避免行读取。
  • 哈希索引数据并不是按照索引值顺序存储的,无法用于排序。
  • 哈希索引也不支持部分索引列匹配查找,因为哈希索引始终是使用索引列的全部内容来计算哈希值的。
  • 哈希索引只支持等值查找。
  • 访问哈希索引的数据非常快,除非有很多哈希冲突。

空间数据索引

地理数据索引。(略)

全文索引

全文索引查找文本中的关键词,一般采用倒排索引。

其他

索引的优点

索引可以让服务器快速的定位到指定的位置。

  • 索引大大减少了服务器需要扫描的数量。
  • 索引可以帮助服务器避免排序和临时表。
  • 索引可以将随机IO变为顺序IO。

参考:Relational Database Index Design and the Optimizers.

索引是最好的解决方案吗?
对于非常小的表,大部分情况下简单的全表扫描更高效。
对于中大型的表,索引就非常有效。
对于特大型的表,建立和使用索引的代价随之增长。可以采用分区技术等。

索引策略

独立的列

索引列不能是表达式的一部分,也不能使函数的参数。

前缀索引和索引选择性

有时候需要索引很长的字符列,会让索引变得很大,这是我们可以使用哈希索引。我们是否还有更好的方法?

通常可以索引开始的部分字符,这样可以节省索引空间,从而提高索引效率。但这样也会降低索引的选择性。

多列索引

很多人对多列索引的理解都不够。一个常见的错误就是,为每个列创建独立的索引,或者按照错误的顺序创建多列索引。

在多个列上建立独立的单列索引大部分情况下并不能提高MySql的查询性能。MySql5.0以上引入了一种“索引合并”的策略,一定程度上可以使用表上的多个单列索引来定位指定的行。

选择合适的索引列顺序

经验法则:将选择性最高的列放在索引最前列。

聚簇索引

聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。InnoDB的聚簇索引索引实际上在同一个结构中保存了B-Tree索引和物理行。
当表有聚簇索引时,实际上它的数据行保存在索引的叶子节点中。所以,一个表中只能有一个聚簇索引。

聚簇索引的优点:

  • 把相关数据保存在一起
  • 数据访问更快,提高了IO的性能

缺点:

  • 插入速度依赖于插入顺序。
  • 更新索引的代价很高。
  • 插入新行,更新主键或者移动行的时候,面临“页分裂”的问题。
  • 可能导致全表扫描变慢,尤其是行稀疏,也分裂导致数据不连续
  • 二级索引(非聚簇索引)可能比想象的大,因为包含了主键列。

覆盖索引

如果索引的叶子节点已经包含了需要查询的字段,那么还有什么必要再回表查询?如果一个索引包含所有需要查询的字段的值,我们就称为“覆盖索引”。

适应场景:

  • 索引条目通常远小于数据行的大小。
  • 对于IO密集型的范围查询会比随机从磁盘读取每一行数据的IO要小的多。
  • 可内存缓存索引,避免系统调用

使用索引进行排序

当索引的列序列和order by子句的顺序完全一致,并且所有列的排序方向(倒序或正序)都一样时,MySql才能够使用索引来对结果进行排序。如果查询关联多个表时,则只有当ORDER BY子句引用的字段全部为第一个表时,才能使用索引进行排序。ORDER BY 子句和查找型查询的限制是一样的:需要全部满足索引的最左前缀的要求;否则,MySql都需要执行排序操纵,而无法利用索引进行排序。

有一种情况下ORDER BY子句可以不满足索引的最左前缀要求,就是前导列为常量的时候。如果WHERE子句或者JOIN子句中对这些列指定了常量,就可以“弥补”索引的不足。

索引和锁

索引可以让查询锁定更少的行。如果你的查询不需要访问那些不需要的行,那么就会锁定更少的行。

设计原则

选择性特别低,并且经常用到的的作为索引前列

例如性别只有2种选择,但是我们经常会用到。如果没有用到性别查询,我们也可以使用 sex in(‘m’,‘f’)来让mysql选择该索引。

有一点需要注意的是,使用in的方式覆盖不在where条件中查询的列,不能过度使用。因为每增加一个in条件,优化器都需要以指数的形式增加,abc。

对于经常性范围查询,应放到索引后列

对于范围查询,MySql无法再使用范围列后面的其他索引了,但是对于多个“等值条件查询”则没有这个限制。
例如年龄查询,可能是查询某个范围的,我们就要放到后面。

避免多个范围查询

使用in来代替多范围查询

优化排序

对于选择性非常低的列,可以添加一些特殊的索引进行排序。
例如sex进行排序时,可以使用(sex,rating)索引进行排序。
select from table where sex=’M’ order by rating ;

PS:本文总结来自《mysql高性能》一书