8.3.1-MySQL是怎样使用索引的

索引被用来快速查找具有特定列值的记录。如果没有索引,MySQL必须从第一条记录开始,读取整张表来获取相关记录。表越大,成本越高。如果一张表在相关列上有索引,就可以快速查找到相关数据,而不用查找整张表。这比扫描每一条记录快多了。

大多数MySQL的索引(PRIMARY KEY,UNIQUE,INDEX, 和FULLTEXT)存储在B-trees。除了:空间数据类型上的索引使用R-trees;MEMORY表也支持哈希索引;InnoDB的全文索引使用倒序列表。

言而总之,下面将会介绍索引是被怎样使用的。哈希索引相关的特性在章节8.3.9(“Comparison of B-Tree and Hash Indexes”)中介绍。

在以下操作中,MySQL使用索引:

  • 快速查找匹配where条件的记录。
  • 用来排除要考虑的记录。如果有多个索引,MySQL会选择那个查找的结果集更少的索引(选择性更好的索引)。
  • 如果相关表有一个联合索引,索引的任何一个最左前缀都可以用来优化查找。例如,如果你有一个三列索引(col1,col2,col3),以下前缀都可以用于快速索引查找:(col1),(col1,col2),(col1,col2,col3). 想了解更多,请查阅8.3.6 “Multiple Column Indexes”。
  • 在执行连接查询时从其他获取记录。如果相关列的类型和大小一致,MySQL可以在相关列上更高效的使用索引。在这种场景下,如果varchar和char的声明长度相同,会被当成一样的。例如,varchar(10)和char(10)大小相同,但是varchar(10)和char(15)不同。 如果是比较nonbinary string列,相关列应该使用相同的字符集。例如,utf8mb4列和latin1列比较,无法使用索引。在比较不同类型的列时(例如,字符串类型的列和时间类型的列或数字类型的列相比较),如果对应的值无法直接比较,就可能无法使用索引。例如,一个字符类型的列值为1,它与具有以下值的string类型列比较时是相同的:‘1’,’ 1’,‘0001’,或'01.e1’。这就排除了字符串列使用索引的可能性。
  • 查找一个特定的索引列key_col上的最大值和最小值。预处理器会检查key_col之前的列是否都和常数值进行了比较。这种情形下,对于每一个min()或max(),MySQL都做了一个简单的索引查找,并将它们替换为常数值。如果所有的表达式都被替换为常数值,就能获取到查询结果。例如:
select min(key_part2),max(key_part2) from tbl_name where key_part1=10;
  • 在相关列是前缀列时(例如,order by key_part1,key_part2),对表中的记录进行排序或分组。如果所有的索引列后面都带desc,则会倒序查找。(或者,如果对应的索引是一个倒序索引,读取相关列时就是前向读取。)见章节8.2.1.16 “ORDER BY OPTIMIZATION”,章节8.2.1.17,“GROUP BY Optimization”,以及章节8.3.13, “Descending Indexes”。
  • 在部分场景中,可以不回表就获取到最终结果。(如果一个查询中所有相关列都在某个索引中,那这个索引就被称为覆盖索引。)如果一个查询只使用到了索引上的列,那就可以从索引树上更快的获取结果集:
select key_part3 from tbl_name where key_part1=1

在查询小表,或是对大表的汇总查询,索引就没那么重要了。如果需要访问大部分记录,那顺序读取比从索引读取再回表更快。顺序查找会减少磁盘查找次数,即使不是所有的记录都是查询所需要的。了解详情,见章节8.2.1.23,“避免全表扫描"。