Mysql中的回表查询与索引覆盖

本文详细介绍了MySQL中的回表查询原理,包括InnoDB的聚集索引和普通索引的区别,以及如何通过回表查询找到所需数据。同时,文章探讨了索引覆盖的概念,这是一种避免回表查询的优化策略,通过建立合适的索引,使得查询可以直接从索引中获取所需信息,提高查询效率。最后,强调了覆盖索引在减少数据访问量、优化IO性能等方面的优势。

了解一下MySQL中的回表查询与索引覆盖。

回表查询

要说回表查询,先要从InnoDB的索引实现说起。InnoDB有两大类索引,一类是聚集索引(Clustered Index),一类是普通索引(Secondary Index)。

InnoDB的聚集索引

InnoDB聚集索引的叶子节点存储行记录,因此InnoDB必须要有且只有一个聚集索引。

1.如果表定义了PK(Primary Key,主键),那么PK就是聚集索引。

2.如果表没有定义PK,则第一个NOT NULL UNIQUE的列就是聚集索引。

3.否则InnoDB会另外创建一个隐藏的ROWID作为聚集索引。

这种机制使得基于PK的查询速度非常快,因为直接定位的行记录。

InnoDB的普通索引

InnoDB普通索引的叶子节点存储主键值(MyISAM则是存储的行记录头指针)。

什么是回表查询

假设有个t表(id PK, name KEY, sex, flag),这里的id是聚集索引,name则是普通索引。

表中有四条记录:

idnamesexflag
1sjmA
3zsmA
5lsmA
9wwfB

聚集索引的B+树索引(id是PK,叶子节点存储行记录):

普通索引的B+树索引(name是KEY,叶子节点存储PK值,即id):

普通索引因为无法直接定位行记录,其查询过程在通常情况下是需要扫描两遍索引树的。

select * from t where name = 'lisi';

这里的执行过程是这样的:

粉红色的路径需要扫描两遍索引树,第一遍先通过普通索引定位到主键值id=5,然后第二遍再通过聚集索引定位到具体行记录。这就是所谓的回表查询,即先定位主键值,再根据主键值定位行记录,性能相对于只扫描一遍聚集索引树的性能要低一些。

索引覆盖

索引覆盖是一种避免回表查询的优化策略。具体的做法就是将要查询的数据作为索引列建立普通索引(可以是单列索引,也可以一个索引语句定义所有要查询的列,即联合索引),这样的话就可以直接返回索引中的的数据,不需要再通过聚集索引去定位行记录,避免了回表的情况发生。

覆盖索引的定义与注意事项

如果一个索引覆盖(包含)了所有需要查询的字段的值,这个索引就是覆盖索引。因为索引中已经包含了要查询的字段的值,因此查询的时候直接返回索引中的字段值就可以了,不需要再到表中查询,避免了对主键索引的二次查询,也就提高了查询的效率。

要注意的是,不是所有类型的索引都可以成为覆盖索引的。因为覆盖索引必须要存储索引的列值,而哈希索引、空间索引和全文索引等都不存储索引列值,索引MySQL只能使用B-Tree索引做覆盖索引。

另外,当发起一个被索引覆盖的查询(索引覆盖查询)时,在explain(执行计划)的Extra列可以看到【Using Index】的信息。

覆盖索引的优点

1.索引条目通常远小于数据行的大小,因为覆盖索引只需要读取索引,极大地减少了数据的访问量。

2.索引是按照列值顺序存储的,对于IO密集的范围查找会比随机从磁盘读取每一行数据的IO小很多。

3.一些存储引擎比如MyISAM在内存中只缓存索引,数据则依赖操作系统来缓存,因此要访问数据的话需要一次系统调用,使用覆盖索引则避免了这一点。

4.由于InnoDB的聚簇索引,覆盖索引对InnoDB引擎下的数据库表特别有用。因为InnoDB的二级索引在叶子节点中保存了行的主键值,如果二级索引能够覆盖查询,就避免了对主键索引的二次查询。

MySQL 中的查询”和“索引覆盖”是数据库查询性能密切相关的重要概念,理解它们的区别及其优化方法有助于提升数据库的整体效率。 ### 查询MySQL 使用非主键索引来查找数据时,通常需要先通过该索引找到记录的主键 ID,然后再利用主键 ID 去主键索引中查找完整的行数据。这个过程被称为“”。查询会增加一次额外的 I/O 操作,因为不仅要访问辅助索引树,还要再次访问主键索引树来获取完整记录的信息。这种操作在处理大量数据或高并发场景下可能会显著影响性能[^4]。 例如,在一个用户信息 `users` 中,如果创建了基于 `name` 字段的索引,并执行如下查询: ```sql SELECT name, age FROM users WHERE name = 'John Doe'; ``` 若 `age` 字段未包含在 `name` 的索引中,则 MySQL 需要进行查询以获取 `age` 数据[^2]。 ### 索引覆盖 索引覆盖是一种优化策略,指的是查询所需的全部字段都存在于某个索引中。在这种情况下,MySQL 可以直接从索引中读取所有需要的数据,而无需中查找完整记录,从而避免了操作带来的性能开销。这种方式可以极大地减少磁盘 I/O 和提高查询速度,尤其是在涉及大量数据的情况下[^3]。 例如,如果对 `users` 创建了一个包含 `name` 和 `age` 的复合索引,并执行相同的查询语句: ```sql SELECT name, age FROM users WHERE name = 'John Doe'; ``` 此时,由于查询的所有字段都在索引中,因此可以直接从索引中获取结果,不需要查询[^2]。 ### 优化方法 为了有效优化数据库查询性能,可以通过以下方式减少查询并尽可能实现索引覆盖: 1. **设计合理的复合索引**:根据常用的查询模式,创建包含多个字段的复合索引。确保查询中涉及的所有字段都被包含在索引中,这样可以充分利用索引覆盖的优势。需要注意的是,复合索引的设计应遵循最左前缀原则,以支持多种查询组合[^3]。 2. **选择性地添加字段到索引**:对于频繁查询且返少量记录的字段,可以在索引中加入一些非查询条件但需要返的字段(即所谓的“覆盖索引”),以便完全避免操作。然而,这也可能导致索引体积增大,进而影响写入性能,因此需权衡查询更新的需求。 3. **避免不必要的字段查询**:在编写 SQL 查询语句时,尽量只选择真正需要的字段,而不是使用 `SELECT *`。这不仅可以减少数据传输量,还能更容易实现索引覆盖,从而提升查询效率。 4. **监控和分析查询计划**:使用 `EXPLAIN` 命令分析查询执行计划,检查是否发生了操作以及索引的使用情况。根据分析结果调整索引结构或查询语句,进一步优化性能。 综上所述,查询是由于索引无法提供查询所需的所有数据而导致的额外查找步骤,而索引覆盖则是通过合理设计索引来消除操作的一种优化手段。两者之间的区别在于是否能够在不访问数据的情况下完成查询任务。通过精心设计索引和优化查询语句,可以有效地减少次数并最大化索引覆盖的应用范围,从而显著提升 MySQL查询性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值