# 总结

通过本章来看,索引是一个非常复杂的话题。MySQL 和存储引擎访问数据的方式,加上索引的特性,使得索引称为一个影响数据访问的有力而灵活的工作(无论数据是在磁盘中还是在内存中)

在 MySQL 中,大多数情况下都会使用 B-Tree 索引。其他类型的所以大多只适合特殊目的。在合适的场景中使用索引,将大大提高查询的响应时间。

值的回顾一下这些特性以及如何使用 B-Tree 索引:

  1. 单行访问是很慢的

    特别是在机械硬盘存储中(SSD 的随机 I/O 要快很多,不过这任然成立)。如果服务器读取一个数据块只为了获取其中一行,那么久浪费了很多工作。最好读取的块中能包含尽可能多需要的行。使用索引可以创建位置引用提升效率

  2. 按顺序访问范围数据是很快的。

    这有两个原因:

    1. 顺序 I/O 不需要多次磁盘寻道,所以比随机 I/O 要快很多(特别是针对机械硬盘)

    2. 如果服务器能按顺序读取数据,那么久不再额外的排序操作,并且 group by 查询也无须再做排序和将行按组进行聚合计算了。

    3. 索引覆盖查询时很快的

      如果一个索引包含了查询需要的多有的列,那么存储引擎就不再需要回表查找行。这避免了大量的单行访问,而上面第 1 点已经写明单行访问是很慢的。

    总的来说,编写查询语句时 应尽可能选择合适的索引以避免单行查找尽可能使用数据原生顺序从而避免额外的排序操作,并尽可能使用索引覆盖查询。这与「三星系统」是一致的思想。

理解索引式如何工作非常重要,应该根据这些理解来创建最合适的索引,而不是根据一些诸如 在多列索引中将选择性最高的列放在第一列应该为 where 子句中出现的所有列创建索引 之类的模糊的经验法则。

**如何判断一个系统创建的索引式合理的呢?**一般来说,建议按照响应时间来对查询进行分析。

  • 找出那些 消耗最常时间的查询 或则那些给服务器 带来最大压力的查询(第三章中介绍了如何测量)
  • 然后检查这些查询的 schema、SQL 和索引结构
  • 判断是否有查询扫描了太多的行
  • 是否做了很多额外的排序或则使用了临时表,
  • 是否使用随机 I/O 访问数据
  • 是否有太多回表查询那些不在索引中的列操作

如果一个查询 无法从所有可能的索引中获益,则应该看看 是否可以创建一个更合适的索引 来提升性能。如果不行,也可以看看是否可以 重写该查询,将其 转化 成一个 能够高效利用现有索引或则新创建索引的查询。这也是下一章要讲解的内容。

如果根据第 3 章介绍给予响应时间的分析不能找出有问题的查询呢?是否可能我们没有注意到「很糟糕」的查询,需要一个更好的索引来获取更高的性能?一般来说,不可能。对于诊断时住不到的查询,那就不是问题。但是,这个查询未来有可能会成为问题,因为应用程序、数据和负载都在变化。如果仍然想找到那些索引不是很合适的查询,并在他们成为问题前进行优化,则可以使用 pt-query-digest 的查询审查「review」功能,分析其 explain 出来的执行计划。