A1:
覆盖索引(Covering Index)是指一个索引包含了查询所需的所有字段,从而可以直接通过索引来获取查询结果,而不需要再回表(访问表中的数据行)。换句话说,覆盖索引能够“覆盖”查询中所有涉及的列,因此查询可以完全依赖索引,提高查询效率。
通常情况下,在查询数据时,数据库会首先使用索引找到符合条件的行对应的物理地址,然后回表(也称为“回表查询”)去表中查找其他非索引字段的数据。但是如果查询所涉及的所有字段都在索引中存在,那么数据库就无需回表,从而加速查询。
假设有一个 users
表,如下:
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100),
age INT
);
我们为 name
和 email
列创建一个组合索引:
CREATE INDEX idx_name_email ON users(name, email);
如果我们有如下查询:
SELECT name, email FROM users WHERE name = 'John';
在这种情况下,查询只涉及 name
和 email
两个字段,这两个字段已经包含在索引 idx_name_email
中,因此数据库可以直接从索引获取结果,不需要再访问表的数据,这就是一个覆盖索引。
覆盖索引特别适合频繁查询的场景,尤其是查询的字段较少且固定的情况下,例如:
覆盖索引能够通过减少回表查询提高查询性能,是数据库优化中的常用技术。适当利用覆盖索引可以显著提升读性能,但在设计时需要权衡索引占用空间和维护成本。
A2:
当查询所涉及的所有字段都在索引中存在时,数据库无需回表的原因在于,索引本质上已经包含了查询所需的数据,能够直接返回结果。这涉及索引的结构和存储方式,具体原因如下:
索引不仅仅是一个指向数据表中行的指针,它本身也包含了部分或全部字段的数据。对于普通的 非聚集索引(non-clustered index),索引记录包含索引列的值以及对应的行位置(或者主键值,称为“行定位符”)。如果查询只涉及索引中的字段,那么数据库可以直接从索引中返回结果。
当查询的所有字段都在索引中时,数据库可以通过扫描索引获取查询的结果,而不需要通过索引再去访问表中的完整数据行,这称为“覆盖索引”的情况。由于索引通常比整个表小得多,直接通过索引返回数据避免了多余的表数据读取,这大大减少了 I/O 操作,提高了查询速度。
通常情况下,索引只包含特定列的数据以及行指针,因此在查询涉及非索引字段时,数据库需要通过索引找到数据行的位置,然后回表查找非索引列的值,这个过程称为“回表”。回表通常通过聚集索引(或主键)找到对应的物理数据行。如果所有的查询字段都在索引中,数据库就不再需要执行这一步骤。
以一个非覆盖索引的查询过程为例:
SELECT name, age FROM users WHERE name = 'John';
假设在 name
列上有一个索引 idx_name
。查询时,数据库首先使用 idx_name
找到满足条件的记录对应的数据行位置,但因为查询中还需要 age
列,而 age
并不在索引中,所以数据库必须根据行位置回表查找该行的完整数据,获取 age
值。
现在,如果我们建立了一个包含 name
和 age
的组合索引:
CREATE INDEX idx_name_age ON users(name, age);
执行相同查询时:
SELECT name, age FROM users WHERE name = 'John';
由于 name
和 age
都包含在索引 idx_name_age
中,数据库可以直接通过索引返回查询结果,无需再访问表中的数据行,这就是覆盖索引的效果。
数据库查询不需要回表的前提是查询所涉及的所有字段都在索引中存在。这样一来,数据库可以直接从索引中读取数据,避免了从表中检索完整数据行的额外步骤,从而显著提高查询效率。