一文带你分清MySQL回表查询与索引覆盖

 更新时间:2023年07月06日 11:51:01   作者:架构精进之路  
这篇文章主要给大家详细介绍如何分清MySQL回表查询与索引覆盖,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1、两类索引

为了更好地阐释这个问题,我们还是从索引来介绍吧。

InnoDB 索引分为两大类,一类是聚集索引(Clustered Index),一类是非聚集索引(Secondary Index)

1.1 聚集索引(聚簇索引)

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

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

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

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

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

1.2 非聚集索引(普通索引、非聚簇索引、二级索引)

普通索引也叫二级索引,除聚簇索引外的索引,即非聚簇索引。

InnoDB的普通索引叶子节点存储的是主键(聚簇索引)的值,而MyISAM的普通索引存储的是记录指针。

Q:为什么非主键索引结构叶子结点存储的是主键值?

A:减少了出现行移动或者数据页分裂时二级索引的维护工作(当数据需要更新的时候,二级索引不需要修改,只需要修改聚簇索引,一个表只能有一个聚簇索引,其他的都是二级索引,这样只需要修改聚簇索引就可以了,不需要重新构建二级索引)

在使用非聚集索引时,为了取到具体数据,则需要通过PK回到聚集索引里去查询数据。这就叫回表查询,扫描了2次索引树,所以效率相对较低。

2、应用示例

一例胜千言,show me you code!

2.1 建表操作

mysql> create table user(
    -> id int(10) auto_increment,
    -> name varchar(30),
    -> sex tinyint(4),
    -> type varchar(8),
    -> primary key (id),
    -> index idx_name (name)
    -> )engine=innodb charset=utf8mb4;

id 字段是聚簇索引,name 字段是普通索引(二级索引)

2.2 填充数据

mysql> select * from user;
+----+--------+------+------+
| id |  name  |  sex | type |
+----+--------+------+------+
| 1 | sj  |  m  |  A  |
| 3 | zs  |  m  |  A  |
| 5 | ls  |  m  |  A  |
| 9 | ww  |  f  |  B  |
+----+-----+-----+-----+

2.3 索引结构

  • 聚簇索引(ClusteredIndex)

id 是主键,所以是聚簇索引,其叶子节点存储的是对应行记录的数据

  • 普通索引(secondaryIndex)

name 是普通索引(二级索引),非聚簇索引,其叶子节点存储的是聚簇索引的的值

2.4 查找过程

  • 普通索引查找过程

如果查询条件为主键(聚簇索引),则只需扫描一次B+树即可通过聚簇索引定位到要查找的行记录数据。

select * from user where name = 'lisi';

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

实际执行过程:

路径需要扫描两遍索引树,第一遍先通过普通索引定位到主键值id=5,然后第二遍再通过聚集索引定位到具体行记录。

这就是所谓的回表查询,即先定位主键值,再根据主键值定位行记录,性能相对于只扫描一遍聚集索引树的性能要低一些。

3、索引覆盖

索引覆盖是一种避免回表查询的优化策略。

只需要在一棵索引树上就能获取SQL所需的所有列数据,无需回表,速度更快。

3.1 如何实现覆盖索引

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

explain select id, name from user where name = 'lisi';

explain分析:因为name是普通索引,使用到了name索引,通过一次扫描B+树即可查询到相应的结果,这样就实现了覆盖索引

- END -

希望今天的讲解对大家有所帮助,谢谢!

到此这篇关于一文带你分清MySQL回表查询与索引覆盖的文章就介绍到这了,更多相关MySQL回表查询与索引覆盖内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • DB为何大量出现select @@session.tx_read_only 详解

    DB为何大量出现select @@session.tx_read_only 详解

    这篇文章主要给大家介绍了关于DB为何大量出现select @@session.tx_read_only 的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-04-04
  • 最新MySQL高级SQL语句大全

    最新MySQL高级SQL语句大全

    这篇文章主要介绍了MySQL高级SQL语句,主要包括常用查询知识order by按关键字排序的sql语句,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • Windows中MySQL root用户忘记密码解决方案

    Windows中MySQL root用户忘记密码解决方案

    在实际应用中,经常会出现忘记mysql管理员用户root的密码的情况出现,那么我们如何来设置一个新密码从而登录数据库呢,下面我们来探讨下
    2014-07-07
  • zabbix监控MySQL主从状态的方法详解

    zabbix监控MySQL主从状态的方法详解

    这篇文章主要介绍了zabbix--监控MySQL主从状态的方法,本文图文并茂给大家介绍的非常详细,具有一定的参考借鉴价值 ,需要的朋友可以参考下
    2019-06-06
  • MySQL如何生成自增的流水号

    MySQL如何生成自增的流水号

    这篇文章主要介绍了MySQL如何生成自增的流水号问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • 教您修复mysql数据库的方法

    教您修复mysql数据库的方法

    你可能在使用MySQL过程中,各种意外导致数据库表的损坏,而且这些数据往往是最新的数据,通常不可能在备份数据中找到。本章将继上篇文章中检查出表的问题后,告诉你如何修复表
    2014-05-05
  • MySQL5.6迁移到DM8的实现示例

    MySQL5.6迁移到DM8的实现示例

    本文主要介绍了MySQL5.6迁移到DM8的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-08-08
  • Mysql多表关联不走索引的原因及分析

    Mysql多表关联不走索引的原因及分析

    这篇文章主要介绍了Mysql多表关联不走索引的原因及分析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • Ubuntu Server下MySql数据库备份脚本代码

    Ubuntu Server下MySql数据库备份脚本代码

    为了mysql数据库的安全,我们需要定时备份mysql数据库,这里提供下脚本代码,需要的朋友可以参考下
    2013-06-06
  • mysql优化取随机数据慢的方法

    mysql优化取随机数据慢的方法

    mysql取随机数据慢,怎么办?下面小编与大家一起来看看mysql取随机数据慢优化的过程。
    2013-11-11

最新评论