你的 SQL 还在回表查询吗?快给它安排上覆盖索引

运维 数据库运维
聚集索引的叶子节点包含完整的行数据,而非聚集索引的叶子节点存储的是每行数据的辅助索引键 + 该行数据对应的聚集索引键(主键值)。

[[422248]]

本文转载自微信公众号「飞天小牛肉」,作者小牛肉。转载本文请联系飞天小牛肉公众号。

什么是回表查询

小伙伴们可以先看这篇文章了解下什么是聚集索引和辅助索引:Are You OK?主键、聚集索引、辅助索引,简单回顾下,聚集索引的叶子节点包含完整的行数据,而非聚集索引的叶子节点存储的是每行数据的辅助索引键 + 该行数据对应的聚集索引键(主键值)。

假设有张 user 表,包含 id(主键),name,age(普通索引)三列,有如下数据:

  1. id name age 
  2. 1 Jack     18 
  3. 7 Alice     28 
  4. 10 Bob      38 
  5. 20 Carry     48 

画一个比较简单比较容易懂的图来看下聚集索引和辅助索引:

  • 聚集索引:

  • 辅助索引(age):

如果查询条件为主键,则只需扫描一次聚集索引的 B+ 树即可定位到要查找的行记录。举个例子:

  1. select * from user where id = 7; 

查找过程如图中绿色所示:

如果查询条件为普通索引(辅助索引) age,则需要先查一遍辅助索引 B+ 树,根据辅助索引键得到对应的聚集索引键,然后再去聚集索引 B+ 树中查找到对应的行记录。举个例子:

  1. select * from user where age = 28; 

上述 select * 等同于 select id, age, name 对吧,id 是主键索引,age 是普通索引,而 name 并不存在于 age 索引的 B+ 树上,所以通过 age 索引查询到 id 和 age 的值之后,还需要去聚集索引上才能查到 name 的值。

如图所示,第一步,查 age 辅助索引:

第二步,查聚集索引:

这就是所谓的回表查询,因为需要扫描两次索引 B+ 树,所以很显然它的性能较扫一遍索引树更低。

什么是覆盖索引

覆盖索引的目的就是避免发生回表查询,也就是说,通过覆盖索引,只需要扫描一次 B+ 树即可获得所需的行记录。

如何实现覆盖索引

上文解释过,下面这个 SQL 语句需要查询两次 B+ 树:

  1. select * from user where age = 28; 

我们将其稍作修改,使其只需要查询一次 B+ 树:

  1. select id, age from user where age = 28; 

之前我们的返回结果是整个行记录,现在我们的返回结果只需要 id 和 age。

id 是什么?主键索引(聚集索引),age 是什么?普通索引(辅助索引),age 索引的 B+ 树的叶子节点存储的是什么?辅助索引键 + 对应的聚集索引键

所以这条 SQL 语句只需要扫描一次 age 索引的 B+ 树就行了

这样,结合这个例子,不知道各位有没有受到启发,如何实现覆盖索引拒绝回表查询呢?

答:联合索引。

我们把 age,name 设置为联合索引:

  1. create index idx_age_name on user(`age`,`name`); 

此时 age 和 name 作为辅助索引键都在同一棵辅助索引的 B+ 树上,所以只需扫描一次这个组合索引的 B+ 树即可获取到 id、age 和 name,这就是实现了索引覆盖

覆盖索引的常见使用场景

在下面三个场景中,可以使用覆盖索引来进行优化 SQL 语句:

1)列查询回表优化(如上面讲的例子,将单列索引 age 升级为联合索引(age, name))

2)全表 count 查询

举个例子,假设 user 表中现在只有一个索引即主键 id:

  1. select count(age) from user

可以用 explain 分析下这条语句,如果 Extra 字段为 Using index 时,就表示触发索引覆盖:

显然现在是没有触发覆盖索引的,我们来优化下:将 age 列设置为索引 create index idx_age on user(age),这样只需要查一遍 age 索引的 B+ 树即可得到结果:

3)分页查询

  1. select id, age, name from user order by username limit 500, 100; 

对于这条 SQL,因为 name 字段不是索引,所以在分页查询需要进行回表查询。

Using filesort 表示没有使用索引的排序,或者说表示在索引之外,需要额外进行外部的排序动作。看到这个字段就应该意识到你需要对这条 SQL 进行优化了。

使用索引覆盖优化:将 (age, name) 设置为联合索引,这样只需要查一遍 (age, name) 联合索引的 B+ 树即可得到结果。

 

责任编辑:武晓燕 来源: 飞天小牛肉
相关推荐

2020-02-14 18:10:40

MySQL索引数据库

2019-04-08 14:58:36

数据库SQL数据类型

2019-07-28 20:49:37

回表查询索引覆盖MySQL

2014-01-09 14:52:47

创意开源

2022-03-15 08:36:46

递归查询SQL

2017-09-05 12:44:15

MySQLSQL优化覆盖索引

2011-04-22 14:45:45

SQL索引

2019-11-26 09:05:32

Python机器学习深度学习

2010-07-07 11:28:12

SQL Server索

2012-07-19 10:03:32

2010-12-20 09:26:44

SQL索引

2021-11-29 11:11:45

SQL查询技巧

2010-11-23 10:53:40

骑驴找马

2023-11-03 08:28:19

2015-03-04 10:49:30

2010-09-28 15:34:05

SQL表结构

2010-09-26 15:23:24

SQL语句

2024-03-29 08:10:43

索引失效SQL

2023-01-03 08:36:34

MySQL索引

2023-09-22 10:05:32

点赞
收藏

51CTO技术栈公众号