这里写目录标题

事故现场

解决方案

提到的“回表查询”

InnoDB的索引

什么是回表查询

怎么优化回表查询

事故现场

数据库使用的MySQL,有一个日志表,需要进行分页查询,于是很容易就想到了limit [offset偏移量] [count数量]这个查询方式,当我们偏移量比较小时,似乎是没什么问题

SELECT* FROMt_log WHEREtype = 1 LIMIT 5, 50

查询时间:0.45s

但是随着offset的增加,就出现了查询时间越来越长,但是每次查出的数据都只有50条,这就让我特别不理解

SELECT* FROMt_log WHEREtype = 1 LIMIT 500000, 50

查询时间:57.252s

SELECT* FROMt_log WHEREtype = 1 LIMIT 1000000, 50

查询时间:89.15s

解决方案

查阅资料发现“limit”的工作方式是:

第一步.先查询offset+count条数据;

第二步.再抛弃前offset条数据

但是全字段查询肯定会有回表查询操作,这就导致了进行百万次的回表查询,速度肯定会很慢,于是我的解决思路是,在“第一步”时不进行回表查询,这样会不会效率提高很多,于是把sql改成下面的等效查询。

SELECT*

FROMt_log t

RIGHT JOIN (

SELECT uid

FROM t_log

WHERE type = 1

LIMIT 1000000,50

) tmp ON tmp.uid = t.uid

查询时间:0.64

这下时间缩短了一百倍多,查出来的结果也是正确的,达到了我们要的效果,到此sql已经优化好了。

提到的“回表查询”

上面说到“第一步”中进行了回表查询,什么是回表查询呢?

InnoDB的索引

这里我们不得不先解释一下InnoDB的索引,要从InnoDB的索引实现说起。InnoDB有两大类索引,一类是聚集索引(Clustered Index),一类是普通索引(Secondary Index)

InnoDB聚集索引和普通索引有什么差异?有什么区别呢?

InnoDB的聚集索引

每行数据是存在InnoDB聚集索引的叶子节点上的,因此InnoDB必须要有且只有一个聚集索引,下面聚集索引的生成规则:

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

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

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

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

InnoDB普通索引

InnoDB普通索引的叶子节点存储主键值。想拿到行数据,还得去聚集索引中扫描索引树。

注意,不是存储行记录头指针,MyISAM的索引叶子节点存储记录指针。

什么是回表查询

下面举个例子解释:

假设有个表user(id PK,name,code),id是聚集索引,code是普通索引。表中有几条数据。

id

name

code

-----

1

小明

AQ

-----

4

小陈

DR

-----

7

小红

CY

-----

9

小刘

FP

-----

那么两种索引的B+树索引就是如下图这样:

从普通索引无法直接定位行记录,那普通索引的查询过程是怎么样的呢?

例:select * from user where code = 'CY';

其查询过程在通常情况下是需要扫描两遍索引树的,这里的执行过程是这样的:

如带色的路径:

第一遍先通过普通索引定位到主键值

然后第二遍再通过聚集索引定位到具体行记录。

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

怎么优化回表查询

那怎么样解决这个性能低的问题呢?这就涉及到一个概念---------覆盖索引

覆盖索引

覆盖索引就是是一种避免回表查询的优化策略。就是把所有需要查询的字段都放到普通索引中,这样普通索引查到的叶子结点(即上图中的黑色方框)中已经能够得到所需的所有字段,就不会再去聚集索引中再查询。

实现覆盖索引的方式

可分为两种:

第一种减少查询字段只查询缩影有的字段,例如我们上面提到的使用limit查询,我们只查了id字段,这样几百万条数据就不会回表查询,外层查询时只有50条数据去聚集索引里进行了查询。又如上面的user表 优化sql为不查询name字段。

例:select id,code from user where code = 'CY';

第二种方式就是修改表创建的索引,增加需要查询的字段,如上面user表,把name也加到索引中,设置(name,code)两个字段的联合索引 。

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

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

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

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

覆盖索引的优点

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

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

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

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

关注公众号,每天进步一点点!

mysql 回表查询优化_MySQL中的回表查询与索引覆盖:一次百万级别分页查询使用Limit 从90秒到0.6毫秒的优化...相关推荐

  1. mysql数据表案例_mysql中库和表的简单操作案例

    mysql中库和表的简单操作案例 发布时间:2020-12-05 09:54:06 来源:亿速云 阅读:71 作者:小新 这篇文章主要介绍mysql中库和表的简单操作案例,文中介绍的非常详细,具有一定 ...

  2. mysql修改表中文名_MySQL中如何修改表的名字?修改表名?

    需求描述 今天在进行MySQL表的历史数据迁移,需要将某张表进行备份,修改表的名字,在此记录下操作过程. 操作过程 mysql> create table ts01 like ti_o_sms; ...

  3. mysql 视图列信息_MySQL 中获取用户表、用户视图、用户表中列信息

    /// ///MySql 数据库维护中心/// public classMySqlDbMaintenance:DbMaintenanceProvider {/// ///获取视图信息列表 Sql语句/ ...

  4. mysql 两张表差集_mysql中两张表使用left join on 求差集详解

    1.表结构 mysql> select * from allStudents; +----+-------+ | id | name | +----+-------+ | 1 | ???? | ...

  5. mysql获取当月最后一天_mysql中获取本月第一天、本月最后一天、上月第一天、上月最后一天

    mysql获取当月最后一天_mysql中获取本月第一天.本月最后一天.上月第一天.上月最后一天等等 转自: https://blog.csdn.net/min996358312/article/det ...

  6. mysql inserted表_触发器中的inserted表和deleted表

    触发器语句中使用了两种特殊的表:deleted 表和 inserted 表.Microsoft? SQL Server 2000 自动创建和管理这些表.可以使用这两个临时的驻留内存的表测试某些数据修改 ...

  7. MySQL-回表查询与索引覆盖

    转自:https://www.cnblogs.com/yanggb/p/11252966.html mysql中的回表查询与索引覆盖 了解一下MySQL中的回表查询与索引覆盖. 回表查询 要说回表查询 ...

  8. mysql 回表查询优化_MySQL优化:如何避免回表查询?什么是索引覆盖?

    转自:https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651962609&idx=1&sn=46e59691257 ...

  9. mysql 回表查询优化_mysql:若何行使笼罩索引制止回表优化查询

    说到笼罩索引之前,先要领会它的数据结构:B+树. 先建个表演示(为了简朴,id按顺序建): id name 1 aa 3 kl 5 op 8 aa 10 kk 11 kl 14 jk 16 ml 17 ...

最新文章

  1. 使用OpenCV进行图像全景拼接
  2. 【cocos2d-x从c++到js】21:使用CocosCode调试JSB
  3. DeepMind发布最新原始音频波形深度生成模型WaveNet,将为TTS带来无数可能
  4. 斯坦福:「目标检测」深度学习全面指南
  5. php一个英文几个字符,PHP指定截取字符串中的中英文或数字字符的实例分享
  6. org.eclipse.jdt.internal.compiler包下的类找不到
  7. nginx正向代理 反向代理
  8. CentOS 安装JDK跟TOMCAT
  9. epoll nio区别_高性能网络服务器编程:为什么linux下epoll是最好,Netty要比NIO.2好?...
  10. Robot Framework(十四) 扩展RobotFramework框架——创建测试库
  11. android 实现代码混淆
  12. 陈彬 2019-1-17
  13. MATLAB调用电脑摄像头前安装图像采集工具箱硬件支持包
  14. codevs1253 超级市场(dp)
  15. xpath 解析后和原网页结构不一致
  16. 分享一些免费的网站速度测试工具
  17. 【Keras】Keras中fit_generator的使用,及fit、fit_generator、和train_on_batch的区别
  18. 经典兔子问题有一对兔子从出生后第3个月起每个月都生一对兔子
  19. Dynamics crm2013 IFD部署后启用多组织
  20. Elasticsearch常见报错和处理方法

热门文章

  1. python基础(part5)--容器类型之字符串
  2. java中文乱码 寮犱笁_MySQL命令窗口中文乱码或插入中文数据失败
  3. 125KHz 100cm ID 读卡电路_智能卡制作频率13.25MHZ与125KHZ的区别
  4. 10分钟学会用Python轻松玩转Excel
  5. SAP Spartacus 项目执行 yarn build --stats-json 遇到的一些错误消息
  6. SAP BTP SDK for Android 已经支持 Kotlin 了
  7. SAP Spartacus Page Layout - 页面布局设计
  8. SAP CRM 查询单据的时候 BAdI 里面的排序字段为何有些不生效
  9. SAP Spartacus list item点击之后的detail页面跳转
  10. 微信开发系列之一 - 微信公众号开发的开发环境搭建