索引覆盖
索引覆盖是指查询操作可以完全通过索引来完成,而无需访问表中的数据行。当一个查询的所有数据需求都可以通过索引中的数据来满足时,就发生了索引覆盖。这样,数据库就不需要进行额外的数据查找,从而减少了磁盘I/O操作,提高了查询性能1。
例如,如果有一个查询语句是:
SELECT name, age FROM users WHERE name = '张三';
如果name和age都包含在一个索引中,那么这个查询就可以通过索引覆盖来完成,不需要回表查询。
索引下推
索引下推是MySQL 5.6及以上版本引入的优化技术。它允许在索引遍历过程中应用查询条件,从而减少访问不必要数据的次数。这意味着数据库引擎会在索引层面过滤数据,而不是在找到所有可能的索引后再在服务器层面进行过滤2。
例如,对于查询:
SELECT * FROM users WHERE name LIKE '张%' AND age = 30;
在启用索引下推的情况下,数据库引擎会在遍历索引时直接应用age = 30的条件,而不是在找到所有姓张的记录后再进行过滤。
重要考虑事项
索引覆盖的一个关键要求是查询中的所有列都必须在索引中。如果查询引用了索引中没有的列,那么就无法实现索引覆盖。
索引下推可以显著减少因为回表操作而导致的性能开销。它通过在存储引擎层面进行更多的数据过滤,减少了服务器层面的工作量。
在设计索引时,应该考虑查询模式,以便最大限度地利用索引覆盖和索引下推的优势。
回表
回表查询是数据库操作中的一个术语,特别是在使用索引进行数据检索时。它发生在使用非聚集索引(Secondary Index)进行查询时,索引中只包含了索引列的副本以及指向对应主键的引用。当查询语句中需要返回的列不在索引列上时,即使通过索引定位了相关行,仍然需要回表获取其他列的值。这意味着数据库需要进行两次查找:一次在非聚集索引上定位数据,一次在聚集索引或主键索引上获取完整的数据行。
代码示例
在MySQL中,如果有一个表,其中id是主键,而name有一个普通索引。当执行如下查询时:
SELECT * FROM table WHERE name = 'ls';
由于name列有一个普通索引,查询会首先使用这个索引。但是,普通索引只存储了name值和对应的主键id,并没有sex和type等其他信息。因此,数据库需要回到主键索引上,根据id再次查询以获取完整的数据行。
优化方法
为了避免回表查询,可以使用索引覆盖。这意味着查询涉及的所有列都包含在索引中,从而避免了第二次查询。例如,如果查询只涉及id和name:
SELECT id, name FROM table WHERE name = 'ls';
这样就不会发生回表查询。但如果查询包括sex列:
SELECT id, name, sex FROM table WHERE name = 'ls';
就需要回表查询,因为sex不在name索引中。解决这个问题的方法是创建一个包含name和sex的联合索引。