Welcome

首页 / 数据库 / MySQL / Schema的优化和索引 - 高性能的索引策略 - 覆盖索引(Covering Indexes)

Schema的优化和索引 - 高性能的索引策略 - 覆盖索引(Covering Indexes)2010-05-30 javaeye.com 风雪涟漪索引是高效找到行的一个方法,但是MySQL也能使用索引找到一个列的数据,因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据;当能通过读取索引就可以得到想要的数据,那就不需要读取行了。一个索引包含了(或覆盖了)满足查询结果的数据就叫做覆盖索引(covering indexex)

覆盖索引是非常强大的工具并且可以大幅度提升性能。考虑下仅仅读取索引的好处:

索引的实体往往小于整个行的大小。如果MySQL仅仅读取索引,意味着访问的数据就非常少了。这对于缓存的工作非常有用,这样相应的时间基本都是来自复制数据而已。对于IO限制也非常有用,因为索引要比数据更小并且更容易的写入内存中。(这对于MyISAM尤其有效,它可以对索引进行压缩,这样索引就变得更小了)。

索引是根据索引值的来排序的,因此IO限制范围的访问相对比从随机硬盘位置所需的IO是较少的。对于一些存储引擎,比如MyISAM,你甚至可以用OPTIMIZE这个表来获取全部的排序索引。这样可使简单的范围查询使用完全连续的索引的访问。

大部分存储引擎缓存索引要好于数据。一些存储引擎,比如MyISAM只缓存索引。因为缓存了MyISAM的数据,访问数据需要一个系统的调用。这样会导致非常严重的性能问题。尤其对于缓存来说,系统的调用是数据访问消耗最大的一部分。

覆盖索引对与InnoDB表有些特殊的效用。因为InnoDB是聚簇索引。InnoDB的次要索引在它们叶子节点保存了行的主键。因此,次要索引的覆盖可以避免在主键上另一个索引的查找。

在这些场景中,从索引中满足一个查询消耗要比查询行要低很多。

覆盖索引也并不适用于任意的索引类型,索引必须存储列的值。Hash, spatial, 和full-text索引不存储值,因此MySQL只能使用B-TREE。并且不同的存储引擎实现覆盖索引都是不同的。并不是所有的存储引擎都支持它们。

当一个查询被索引所覆盖。(an index-covered query)。你使用EXPLAIN就会发现EXTRA列的值为“Using index”。一个例子,sakila.inventory表由一个多列的索引在store_id, film_id的列上。MySQL能使用索引来访问这两列。如下

mysql> EXPLAIN SELECT store_id, film_id FROM sakila.inventoryG
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: inventory
type: index
possible_keys: NULL
key: idx_store_id_film_id
key_len: 3
ref: NULL
rows: 4673
Extra: Using index

覆盖索引的语句有些诡异的是会关闭优化。MySQL语句优化器在执行语句之前会决定是否有一个索引覆盖它。假使这个索引覆盖了一个WHERE条件,但是并不是整个查询。如果这个条件评估为false,MySQL51以及以前版本都会取出行。

让我们来看看为什么会这样。以及怎样重写这个查询来解决上面所说的问题。

mysql> EXPLAIN SELECT * FROM products WHERE actor="SEAN CARREY"
-> AND title like "%APOLLO%"G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: products
type: ref
possible_keys: ACTOR,IX_PROD_ACTOR
key: ACTOR
key_len: 52
ref: const
rows: 10
Extra: Using where