MySQL 分页查询优化——延迟关联优化
目录
1. InnoDB表的索引的几个概念
2. 覆盖索引和回表
3. 分页查询
4. 延迟关联优化
写在前面
下面的介绍均是在选用MySQL数据库和Innodb引擎的基础开展。我们先来学习索引的几个概念,帮助我们理解延迟关联优化的加快分页查询速度的原因。
一、Innodb表的索引的几个概念
InnoDB表是基于聚簇索引建立的。
索引一般分为主键索引和普通索引(辅助索引),聚簇索引并不是主键索引这样的单独的索引类型,而是一种数据存储方式。通俗的来说,单独的索引是存储了索引信息的B+Tree,而聚簇索引是在同一个结构中保存了B+Tree和数据行,即通过主键索引B+Tree的结构建立数据文件(网上的说法是索引和数据存储在同一个文件中),因此聚簇索引是一种数据存储方式。
如果对于索引的概念不是很熟悉,建议去查阅相关资料学习,索引是一个很庞大的知识结构。
Innodb表以主键索引建立后缀名为.MYD表存储文件,普通索引亦以B+Tree实现,并保存在后缀名为.MYI的文件中,具体结构图如下所示:
在查询时选用主键索引和普通索引有什么不一样呢?
以下面语句为例:
·
select * from table where id = 5;(id为主键索引) 检索过程如上图绿色箭头所示,直接在主索引树上根据主键检索
·
select * from table where name = "Gates"; (name为普通索引)检索过程如上图红色箭头所示,先根据普通索引检索普通索引树得到id为5,然后再拿得到的id到主索引树检索得到结果。在这个过程中,回到主键索引树搜索的过程,我们称为回表。
从这里可以看出,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。
解释完普通索引和主键索引的检索过程,让我们来看看什么是覆盖索引。
二、覆盖索引和回表。
什么是“覆盖索引”?
查询的列被所建的辅助索引所覆盖,无需回表。用大白话解释就是,要查的数据直接可以从索引树上就能取得,无需回表查找。
注意:不是所有类型的索引都可以成为覆盖索引。覆盖索引必须要存储索引的列,而哈希索引、空间索引和全文索引等都不存储索引列的值,所以MySQL只能使用B-Tree索引做覆盖索引
结合上图的例子:
·
select id from table where name = "Gates"; 即为一个覆盖索引。
三、分页查询使用场景
需求:查询最近 7 天的订单,并做分页。订单表数据量:3000W。
未经优化的SQL:
select * from t_trade_order
where create_time
between '2019-10-17' and '2019-10-25'
limit 1000000, 10;
根据explain输出的结果可知,这是一条慢查询,在业务环境中不允许出现这样的慢查询。
我们都知道在做分页时会用到Limit关键字去筛选所需数据,limit接受1个或者2个参数,接受两个参数时第一个参数表示偏移量,即从哪一行开始取数据,第二个参数表示要取的行数。
如果只有一个参数,相当于偏移量为0。当偏移量很大时,如limit
100000,10 取第100001-100010条记录,mysql会取出100010条记录然后将前100000条记录丢弃,这无疑是一种巨大的性能浪费。
终于转入正题了,那我们应该怎样优化呢?
四、延迟关联优化
《高性能MySQL》书中其实也讨论这个情况:
延迟关联优化:通过使用覆盖索引查询返回需要的主键,再根据主键关联原表获得需要的数据。
select * from
t_trade_order t
inner join (
select id from t_trade_order
where create_time between '2019-10-17'
and '2019-10-25'
limit 1000000, 10
) e
on t.id = e.id;
根据explain分析,查询时间仅为0.31,比普通的分页查询快了一个数量级。
想必大家会想知道,为什么延迟关联对比普通分页查询可以起到这样的优化效果呢?
这就涉及到上面所讲的覆盖索引和回表这两个重要概念了!
我们来看看这两条语句的执行流程就很清楚了。
优化前:
select * from t_trade_order
where create_time
between '2019-10-17' and '2019-10-25'
limit 1000000, 10;
(create_time建表时被设置为普通索引)
1.在create_time索引树上找到create_time=‘2019-10-17’的记录,取得其id。
2.再到主索引树查到对于id的记录
3.如数量小于10,更新时间,循环步骤1、2
4. 。。。
5.在create_time索引树取下一个值create_time='2019-10-25',不满足条件,循环结束。
6.查询结果放弃前1000000行,返回10行
显然,普通的分页查询是逐一通过普通索引获得id然后回表查询,每次回表进行一次IO,造成相当大的性能浪费。
优化后
select * from
t_trade_order t
inner join (
select id from t_trade_order
where create_time between '2019-10-17' and
'2019-10-25'
limit 1000000, 10
) e
on t.id = e.id;
1.使用覆盖索引,select id
from t_trade_order where create_time between '2019-10-17' and '2019-10-25'
limit 1000000, 10,查询结果放弃前1000000行,返回10行,查询出符合查询范围的id
2、回表关联,根据获得的id关联主索引表,批量匹配得到结果。(只需回到主索引表一次)
由此可知,通过使用覆盖索引查询返回需要的主键,再根据这些主键关联原表获得需要的行,这可以减少MySQL回表的次数,也避免了MySQL直接在原表上扫描那些需要丢弃的行数(实则在普通索引树上扫描,速度快很多)。
文章写到这里,希望对大家理解延迟关联优化有些许帮助。
MySQL 分页查询优化——延迟关联优化的更多相关文章
- mysql大量数据分页查询优化-延迟关联
所有的php初学者都应该知道,mysql的分页语句写法如下: 1 select * from a limit (page-1)*page_size,page_size 而当这语句分页到一定程度时,例如 ...
- 【MySQL】查询优化实例解析-延迟关联优化
[提出问题] 从数据表t通过分页查询的方式读取数据,读取时要根据a1排序.t有80万行记录,当OFFSET很大时,读取速度很慢.优化后查询速度提升很快. 下图是表的定义,一共有几十个字段,RowLen ...
- mysql优化----大数据下的分页,延迟关联,索引与排序的关系,重复索引与冗余索引,索引碎片与维护
理想的索引,高效的索引建立考虑: :查询频繁度(哪几个字段经常查询就加上索引) :区分度要高 :索引长度要小 : 索引尽量能覆盖常用查询字段(如果把所有的列都加上索引,那么索引就会变得很大) : 索引 ...
- mysql分页查询优化(索引延迟关联)
对于web后台报表导出是一种常见的功能点,实际对应服务后端即数据库的排序分页查询.如下示例为公司商户积分报表导出其中一个sql ,当大批量的导出请求进入时候,mysql的cpu急剧上升瞬间有拖垮库的风 ...
- mysql 利用延迟关联优化查询(select * from your_table order by id desc limit 2000000,20)
其实在我们的工作中类似,select * from your_table order by id desc limit 2000000,20会经常遇见,比如在分页中就很常见. 如果我们的sql中出现这 ...
- MySQL 分页查询优化
有时在处理偏移量非常大的分页时候查询时,例如LIMIT 1000,10这样的查询,这时MySQL需要查询1010条记录然后只返回最后10条,前面1000条记录都被抛弃,这样的代价非常高.要优化这种查询 ...
- 复盘MySQL分页查询优化方案
一.前言 MySQL分页查询作为Java面试的一道高频面试题,这里有必要实践一下,毕竟实践出真知. 很多同学在做测试时苦于没有海量数据,官方其实是有一套测试库的. 二.模拟数据 这里模拟数据分2种情况 ...
- MySQL分页查询的性能优化
MySQL limit分页查询的性能优化 Mysql的分页查询十分简单,但是当数据量大的时候一般的分页就吃不消了. 传统分页查询:SELECT c1,c2,cn… FROM table LIMIT n ...
- MYSQL分页 limit 太慢优化
limit分页原理 当我们翻到最后几页时,查询的sql通常是:select * from table where column=xxx order by xxx limit 1000000,20.查询 ...
随机推荐
- 当 K8s 集群达到万级规模,阿里巴巴如何解决系统各组件性能问题?
作者 | 阿里云容器平台高级技术专家 曾凡松(逐灵) 本文主要介绍阿里巴巴在大规模生产环境中落地 Kubernetes 的过程中,在集群规模上遇到的典型问题以及对应的解决方案,内容包含对 etcd.k ...
- 基于docker构建测试环境
目录 0x01介绍 0x02 镜像基本操作 0x03 容器基本操作 0x04 容器的修改与保存 0x05 使用Dockerfile定制镜像 0x01介绍 Docker 是一个开源的应用容器引擎,基于 ...
- Python日志产生器
Python日志产生器 写在前面 有的时候,可能就是我们做实时数据收集的时候,会有一个头疼的问题就是,你会发现,你可能一下子,没有日志的数据源.所以,我们可以简单使用python脚本来实现产生实时的数 ...
- .NET之Hangfire快速入门和使用
前言: 定时任务调度问题,是一个老生常谈的问题.网上有许多定时任务调度的解决方案,对于我而言很早以前主要是使用Window计划和Window服务来做任务定时执行,然后就开始使用定时任务调度框架Quar ...
- MySQL命令窗口出现中文乱码的解决方法
查询表语句的时候,出现了中文乱码,但是用Navicat for MySQL查看的时候却是正常的,字符集都是设置的utf-8,如下图所示: 其实上大学学习java的时候也遇到了中文乱码但是却没有 ...
- shell判断文件目录或文件是否存在
1.文件描述符 -e 判断对象是否存在 -d 判断对象是否存在,并且为目录 -f 判断对象是否存在,并且为常规文件 -L 判断对象是否存在,并且为符号链接 -h 判断对象是否存在,并且为软链接 -s ...
- tomcat设置指定jdk版本
windows 1.解压下载的tomcat; 2.找到bin下的setclasspath.bat文件:在文件的开始出添加如下代码来设定JAVA_HOME和JRE_HOME的路径: set JAVA_H ...
- 死磕 java同步系列之终结篇
简介 同步系列到此就结束了,本篇文章对同步系列做一个总结. 脑图 下面是关于同步系列的一份脑图,列举了主要的知识点和问题点,看过本系列文章的同学可以根据脑图自行回顾所学的内容,也可以作为面试前的准备. ...
- python openpyxl内存不主动释放 ——关闭Excel工作簿后内存依旧(MemoryError)
在openpyxl对Excel读写操作过程中,发现内存没有马上释放,如果得多次读取大文件,内存爪机,后续代码就无法运行. 尝试:各种wb.save()或者with open等途径无法解决. 发现:因为 ...
- Android系统介绍与框架
一.Andriod是什么? Android系统是Google开发的一款开源移动OS,Android中文名被国内用户俗称“安卓”.Android操作系统基于Linux内核设计,使用了Google公司自己 ...