mysql索引(二)----如何高效使用索引

1、索引的优点

索引总结下来有三个:

  1. 索引大大减少了服务器需要扫描的数据量。
  2. 索引可以帮助服务器避免排序和临时表。
  3. 索引可以将所及 I/O 变为顺序 I/O。

2、高效使用索引

不恰当地使用索引,或者无法使用已有的索引,将无法使索引的优势发挥出来。正确使用索引的方式可以非常高效地提高我们查询的速度,下面是几种高效使用索引的方式。

2.1 独立的列

‘’独立的列‘’是指索引列不能是表达式的一部分,也不能是函数的参数。

使用WHERE条件时,要始终将索引列单独放在比较符号的一侧

例如,下面将无法使用 actor_id 列的索引:

mysql> SELECT actor_id  FROM actor WHERE actor_id + 1 = 5;

凭肉眼很容易看出 actor_id = 4,但是MySQL 却无法自动解析这个方程式,所以这个所以并没有被用到。

2.2 前缀索引和索引选择性

索引的选择性是指,不重复的索引值(也称为基数)和数据表的记录总数(#T)的比值,范围是 1/#T 到 1 之间。

例如,求 actor_id 的基数:

mysql> SELECT COUNT(DISTINCT actor_id) / COUNT(*)
	 >FROM actor;

索引的选择性越高则查询效率越高,因为选择性高的索引可以让 MySQL 在查找时过滤掉更多的行。唯一索引的选择性是 1,这是最好的索引选择性,性能也是最好的。

有时候需要索引很长的字符列,这会让索引变得大且慢。为了节约索引空间,从而提高索引效率,通常可以选择只索引开始的部分字符

诀窍在于要选择足够长的前缀以保证较高的选择性,同时又不能太长(以便节约空间)。换句话说,选择的前缀的“基数”应该接近于完整列的“基数”。

不过前缀索引也有缺点

  • MySQL 无法使用前缀索引做 ORDER BY 和 GROUP BY,也无法使用前缀索引做覆盖扫描。

2.3 多列索引

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

在多个列上建立独立的单列索引大部分情况下并不能提高 MySQL 的查询性能。

在 MySQL 5.0 之后,查询能够同时使用多个单列索引进行扫描,并将结果进行合并。这种算法有三个变种:

  • OR 条件的联合(union)
  • AND 条件的相交(intersection)
  • 同时存在 OR 条件和 AND 条件

可以通过 EXPLAIN 中的 Extra 列看到:

索引合并策略有时候是一种优化的结果,但实际上更多时候说明了表上的索引建得很糟糕:

  • 当多个索引做 AND 条件操作时,通常意味着需要一个包含所有相关列的多列索引,而不是多个独立的单例索引。
  • 当多个索引做 OR 条件操作时,通常需要耗费大量 CPU 和内存资源在算法的缓存、排序和合并操作上。特别是当其中有些索引的选择性不高,需要合并扫描大量数据的时候。
  • 更重要的是,优化器不会把这些计算到“查询成本”中。所以通常来说,如果有多个单列索引进行查询,将查询改写成 union 的方式往往更好。当然,最好的办法还是将索引改写成正确的多列索引

2.4 选择合适的索引列顺序

在一个多列 B-Tree 索引中,索引列的顺序意味着索引首先按照最左列进行排序,其次是第二列,等等。

索引可以按照升序或者降序进行扫描,以满足精确符合列顺序的 ORDER BY 、GROUP BY 和 DISTINCT 等子句的查询需求,所以多列索引的列顺序至关重要

对于选择索引列有一个经验法则:将选择性最高的列放在索引最前列。

但是这个并不是放之四海而皆准的法则,场景不同则选择不同。

在不考虑排序和分组时,这个法则通常是很好的。

而 WHERE 子句中的排序、分组和范围条件等因素会对查询的性能造成非常大的影响。

2.5 聚簇索引

之前写过聚簇索引的详细介绍: https://www.cnblogs.com/luler/p/13985408.html

2.6 覆盖索引

如果一个索引包含了所有需要查询的字段的值,我们就称之为“覆盖索引”。

覆盖索引是非常有用的工具,能够极大地提高性能:

  • 索引条目通常远小于数据行大小,所以如果只需要读取索引,那将会极大地减少数据访问量。

  • 因为索引是按列值顺序存储的(至少在单个页内是这样),所以将会大大减少 I/O 。

  • 对于聚簇索引,InnoDB 的二级索引在叶子节点中保存了行的主键值,所以如果二级主键能够覆盖查询,则可以避免对主键索引的二次查询。

不是所有类型的索引都可以成为覆盖索引。

覆盖索引必须存储索引列的值,而哈希索引、空间索引和全文索引等都不存储索引列的值,

所以 MySQL 只能使用 B-Tree 索引做覆盖索引。

当发起一个被索引覆盖的查询时, 在 EXPLAIN 的 Extra 列可以看到 “Using index” 的信息。

例如,下面有一个多列索引 (store_id, film_id):


3、优化查询

3.1 避免多个范围条件

对于 B-Tree 索引而言,如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找。

也就是说,当遇到第一个范围条件查询时,后面的条件则无法用到索引。

所以,如果出现了范围条件查询,一定将它放到最后。

而如果出现多个范围条件,那么就要采取其他方式替代。

3.2 使用IN()条件代替范围查询

对于范围条件查询,MySQL 无法再使用范围列后门的其他索引列了。但是对于 IN() 条件查询则没有这个限制。

例如在查询年龄在18~24岁之间的人,可以使用 IN() 来代替范围查询,改写为 IN(18, 19, 20, 21, 22, 23, 24)。

并不是所有的范围查询都可以转换。这里描述的基本原则是,尽可能将需要做范围查询的列放到索引的后面,以便于优化器能使用更多的索引列。

总结

在 MySQL 中,大多数情况下都会使用 B-Tree 索引,其他类型的索引大多只适用于特殊的目的。

在选择索引和编写索引的查询时,要使用记住这三个原则:

  1. 单行访问是很慢的。最好读取的块中能包含尽可能多所需要的行,使用索引可以创建位置引用以提升效率。
  2. 按顺序访问范围数据是很快的。首先顺序 I/O 不需要多次磁盘寻道,其次如果能够按顺序读取数据,那么就不需要额外的排序操作,并且 GROUP BY 查询也无需再做排序和讲行按组进行聚合计算了。
  3. 索引覆盖查询是很快的。如果一个索引包含了查询需要的所有列,那么存储引擎就不需要再回表查询行。
posted @ 2021-06-30 17:09  乐子不痞  阅读(146)  评论(0编辑  收藏  举报
回到顶部