为什么MySQL分页用limit会越来越慢


Posted in MySQL onJuly 25, 2021

阿牛新入职了一家新公司,第一个任务是根据条件导出订单表中的数据到文件中,阿牛心想:这也太简单了,于是很快写好了如下语句,并且告诉测试自己的代码是免测产品。

语句如下:

select * from orders where name=‘lilei' and create_time>'2020-01-01 00:00:00' limit start,end

没想到上线一段时间后,生产开始预警,显示这条sql为慢SQL,执行时间50多秒,严重影响到了业务。
阿牛赶紧请教大佬猿猿帮忙查找原因,猿猿很快就帮其解决了,并且给阿牛做了以下实验:

一、测试实验

mysql分页直接用limit start, count分页语句:

select * from product limit start, count

当起始页较小时,查询没有性能问题,我们分别看下从10, 100, 1000, 10000开始分页的执行时间(每页取20条),如下:

select * from product limit 10, 20 0.016秒
select * from product limit 100, 20 0.016秒
select * from product limit 1000, 20 0.047秒
select * from product limit 10000, 20 0.094秒

我们已经看出随着起始记录的增加,时间也随着增大, 这说明分页语句limit跟起始页码是有很大关系的,
那么我们把起始记录改为40w看下(也就是记录的一半左右)

select * from product limit 400000, 20 3.229秒

再看我们获取最后一页记录的时间

select * from product limit 866613, 20 37.44秒

像这种分页最大的页码页显然这种时间是无法忍受的。
从中我们也能总结出两件事情:
limit语句的查询时间与起始记录的位置成正比。
mysql的limit语句是很方便,但是对记录很多的表并不适合直接使用。

二、 对limit分页问题的性能优化方法

2.1 利用表的覆盖索引来加速分页查询

我们都知道,利用了索引查询的语句中如果只包含了那个索引列(覆盖索引),那么这种情况会查询很快。
因为利用索引查找有优化算法,且数据就在查询索引上面,不用再去找相关的数据地址了,这样节省了很多时间。
另外Mysql中也有相关的索引缓存,在并发高的时候利用缓存就效果更好了。
在我们的例子中,我们知道id字段是主键,自然就包含了默认的主键索引。现在让我们看看利用覆盖索引的查询效果如何:
这次我们之间查询最后一页的数据(利用覆盖索引,只包含id列),如下:

select id from product limit 866613, 20

查询时间为0.2秒,相对于查询了所有列的37.44秒,提升了大概100多倍的速度。
那么如果我们也要查询所有列,有两种方法,

2.2 利用 id>=的形式:

SELECT * FROM product 
WHERE ID > =(select id from product limit 866613, 1) limit 20

查询时间为0.2秒,简直是一个质的飞跃啊。

2.3 利用join

SELECT * FROM product a 
JOIN (select id from product limit 866613, 20) b ON a.ID = b.id

总结:

是不是认为我没说理由,原因就是使用select * 的情况下直接用limit 600000,10 扫描的是约60万条数据,并且是需要回表60W次,也就是说大部分性能都耗在随机访问上,到头来只用到10条数据,如果先查出来ID,再关联去查询记录,就会快很多,因为索引查找符合条件的ID很快,然后再回表10次。就可以拿到我们想要的数据。

到此这篇关于为什么MySQL分页用limit会越来越慢的文章就介绍到这了,更多相关MySQL分页limit慢内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
MySQL pt-slave-restart工具的使用简介
Apr 07 MySQL
MySQL安装后默认自带数据库的作用详解
Apr 27 MySQL
MySQL 使用自定义变量进行查询优化
May 14 MySQL
MySQL 发生同步延迟时Seconds_Behind_Master还为0的原因
Jun 21 MySQL
MySQL连表查询分组去重的实现示例
Jul 01 MySQL
MySQL系列之开篇 MySQL关系型数据库基础概念
Jul 02 MySQL
MySQL分库分表详情
Sep 25 MySQL
教你如何让spark sql写mysql的时候支持update操作
Feb 15 MySQL
分享MySQL常用 内核 Debug 几种常见方法
Mar 17 MySQL
Nebula Graph解决风控业务实践
Mar 31 MySQL
MySQL 原理与优化之原数据锁的应用
Aug 14 MySQL
MySQL常用慢查询分析工具详解
Aug 14 MySQL
MySQL深度分页(千万级数据量如何快速分页)
ORM模型框架操作mysql数据库的方法
mysql 直接拷贝data 目录下文件还原数据的实现
MySQL索引是啥?不懂就问
MySQL 四种连接和多表查询详解
MySQL 聚合函数排序
MySQL 那些常见的错误设计规范,你都知道吗
Jul 16 #MySQL
You might like
php下批量挂马和批量清马代码
2011/02/27 PHP
php数组函数序列之array_unique() - 去除数组中重复的元素值
2011/10/29 PHP
PHP 正则表达式之正则处理函数小结(preg_match,preg_match_all,preg_replace,preg_split)
2012/10/05 PHP
php解析url的三个示例
2014/01/20 PHP
微信获取用户地理位置信息的原理与步骤
2015/11/12 PHP
javascript中的array数组使用技巧
2010/01/31 Javascript
xheditor与validate插件冲突的解决方案
2010/04/15 Javascript
用JS提交参数创建form表单在FireFox中遇到的问题
2013/01/16 Javascript
js实现网站首页图片滚动显示
2013/02/04 Javascript
初识Node.js
2015/03/20 Javascript
js 判断登录界面的账号密码是否为空
2017/02/08 Javascript
详解Vue2.0之去掉组件click事件的native修饰
2017/04/20 Javascript
vue使用 better-scroll的参数和方法详解
2018/01/25 Javascript
Layui 设置select下拉框自动选中某项的方法
2018/08/14 Javascript
Vue使用axios出现options请求方法
2019/05/30 Javascript
vue动态禁用控件绑定disable的例子
2019/10/28 Javascript
原生js实现点击按钮复制内容到剪切板
2020/11/19 Javascript
Python3.5编程实现修改IIS WEB.CONFIG的方法示例
2017/08/18 Python
python实现随机森林random forest的原理及方法
2017/12/21 Python
详解python使用Nginx和uWSGI来运行Python应用
2018/01/09 Python
python GUI库图形界面开发之PyQt5窗口背景与不规则窗口实例
2020/02/25 Python
Django中的模型类设计及展示示例详解
2020/05/29 Python
Python3读写ini配置文件的示例
2020/11/06 Python
详解Django自定义图片和文件上传路径(upload_to)的2种方式
2020/12/01 Python
HTML5制作3D爱心动画教程 献给女友浪漫的礼物
2014/11/05 HTML / CSS
配置H5的滚动条样式的示例代码
2018/03/09 HTML / CSS
韩国三星旗下的一家超市连锁店:Home Plus
2016/07/30 全球购物
联想新加坡官方网站:Lenovo Singapore
2017/10/24 全球购物
音乐表演专业毕业生求职信
2013/10/14 职场文书
产品促销活动策划书
2014/01/15 职场文书
交通事故赔偿协议书
2014/04/15 职场文书
中秋节活动总结
2014/08/29 职场文书
超市店庆活动方案
2014/08/31 职场文书
CocosCreator如何实现划过的位置显示纹理
2021/04/14 Javascript
分析MySQL抛出异常的几种常见解决方式
2021/05/18 MySQL
Mysql文件存储图文详解
2021/06/01 MySQL