B+ 树中的索引覆盖和索引下推
1. 什么是索引覆盖?
索引覆盖是指数据库查询时,所有查询需要的字段都可以从索引中直接获取,不需要回表查找数据。通俗点说,就是数据库的索引本身已经包含了你需要的“答案”。
举个例子:
假设有一张表 student
,包含以下字段:
id
(主键)name
(名字)age
(年龄)score
(成绩)
现在你在 age
字段上创建了一个联合索引:(age, score)
。
如果你执行如下查询:
SELECT score FROM student WHERE age = 18;
这个时候,数据库发现:
- 你查询的
score
字段和条件age=18
都包含在索引(age, score)
里。 - 不需要再去表里面读取其他字段的数据。
这就叫“索引覆盖”,因为索引已经完全覆盖了查询需要的字段。
为什么索引覆盖很快? 因为不需要来回从磁盘中读取数据表,只需要从索引(比较小且高效的数据存储结构)中读取数据,大大节省了时间。
即使索引覆盖具备高效的查询优势,但在某些情况下,索引覆盖也无法实际被使用。
1. 查询条件不匹配索引设计
如果查询条件和索引的字段顺序或类型不匹配,索引覆盖就无法生效。
举个例子:
假设我们在 student
表上创建了一个联合索引 (age, score)
,用于优化查询。
现在执行以下 SQL:
SELECT score FROM student WHERE score = 90;
为什么索引覆盖无法使用?
- 联合索引
(age, score)
是按照字段顺序建立的。 - 在联合索引中,必须首先根据
age
字段进行查找,score
的条件无法单独利用这个索引。 - 换句话说,查询需要依赖索引的“最左前缀原则”,否则就会失效。
2. 查询字段中有不包含在索引内的字段
如果查询的字段不完全被索引覆盖,即使查询条件使用了索引,数据库仍然需要“回表”查询其他字段,这种情况下无法实现索引覆盖。
举个例子:
还是 student
表,联合索引 (age, score)
已经建立。
现在执行以下 SQL:
SELECT name FROM student WHERE age = 18;
问题在哪里?
- 查询的字段
name
并不在(age, score)
索引中。 - 数据库无法通过索引直接获取
name
,所以必须“回表”查询原表中的数据。 - 因此,即使索引可以筛选
age = 18
的条件,也无法实现索引覆盖。
3. 查询字段使用了函数或运算
如果查询字段经过了某些函数或运算操作,即使索引中有这些字段,索引仍然无法被有效利用。
举个例子:
假设在 age
字段上有一个单独的索引。
执行以下 SQL:
SELECT age FROM student WHERE age + 1 = 19;
为什么索引覆盖失效?
- 条件
age + 1 = 19
需要经过计算(即变成age = 18
),这让索引失去了直接匹配的能力。 - 数据库无法利用索引直接筛选出符合条件的记录。
类似情况:
- 使用了函数,例如
WHERE UPPER(name) = 'TOM'
。 - 使用了范围查询,但涉及到复杂条件,例如
WHERE age BETWEEN 10 AND score + 5
。
4. 查询条件中的数据类型不一致
如果查询条件中的字段和索引字段的数据类型不一致,即使索引存在,也可能无法被有效利用。
举个例子:
假设在 age
字段上有个索引,而 age
是一个整数(INT
)字段。
执行以下 SQL:
SELECT score FROM student WHERE age = '18';
为什么索引覆盖失效?
- 在查询中,
age = '18'
中的18
是字符串类型,而索引中的age
是整数类型。 - 数据库可能需要做隐式的数据类型转换,这会导致索引失效,无法实现索引覆盖。
5. 查询条件过于复杂
如果查询条件非常复杂(例如包含多个 OR 条件、子查询等),即使某些字段有索引,也可能无法实现索引覆盖。
举个例子:
SELECT score FROM student WHERE age = 18 OR name = 'Tom';
为什么索引覆盖失效?
age
有索引,但name
没有索引。- OR 条件会导致数据库需要扫描两个不同的范围,可能无法充分利用索引。
6. 索引不适合特定存储引擎
有些存储引擎(例如 MyISAM 和 InnoDB)对索引覆盖的支持可能存在差异。如果使用的存储引擎不支持“覆盖索引”,即使查询条件完全匹配索引,也可能无法使用索引覆盖。
总结
以下是索引覆盖无法使用的常见情况:
- 查询条件不符合索引的字段顺序(违反最左前缀原则)。
- 查询字段中有不包含在索引中的字段。
- 查询字段涉及函数或运算(导致索引失效)。
- 查询条件的数据类型和索引字段不一致。
- 查询条件过于复杂(例如多个 OR 条件)。
- 存储引擎或索引设计不支持索引覆盖。
什么是最左前缀原则
在实际使用中,合理设计索引结构,并优化查询条件,可以最大化利用索引覆盖的性能优势~ 😊
索引覆盖(Index Covering)的查找流程
2. 什么是索引下推?
索引下推是优化查询效率的一种策略,把条件过滤的工作尽量在索引扫描阶段完成,减少不必要的数据读取。
举个例子:
还是这张 student
表,我们在 age
字段上建立了普通索引。
如果你执行如下查询:
SELECT * FROM student WHERE age > 18 AND score > 80;
索引下推是怎么回事?
- 数据库会先通过
age
的索引,找到所有age > 18
的记录。 - 在扫描索引时,数据库会直接检查
score > 80
这个条件(在索引中能看到score
的值)。 - 只有满足两个条件的记录,才会被“回表”去数据表中读取完整的内容。
什么是回表
没有索引下推时的情况:
- 数据库先通过
age > 18
找到所有可能的记录。 - 然后从表中把所有这些记录拉出来,再检查
score > 80
。
可以看出:
- 有索引下推时,数据表的访问次数减少,查询效率更高。
- 索引下推就像门卫,在大门口就筛选掉无关的记录,只有合格的才放进去。
索引下推(Index Pushdown)的查找流程
总结:
- 索引覆盖:索引能完全满足查询需求,不需要回表,效率高。
- 索引下推:过滤条件尽量在索引阶段完成,减少不必要的回表,提高查询效率。