mysql分页查询关键_MySQL优化教程之超大分页查询

背景

基本上只要是做后台开发,都会接触到分页这个需求或者功能吧。基本上大家都是会用MySQL的LIMIT来处理,而且我现在负责的项目也是这样写的。但是一旦数据量起来了,其实LIMIT的效率会极其的低,这一篇文章就来讲一下LIMIT子句优化的。

LIMIT优化

很多业务场景都需要用到分页这个功能,基本上都是用LIMIT来实现。

建表并且插入200万条数据:

# 新建一张t5表

CREATE TABLE `t5` (

`id` int NOT NULL AUTO_INCREMENT,

`name` varchar(50) NOT NULL,

`text` varchar(100) NOT NULL,

PRIMARY KEY (`id`),

KEY `ix_name` (`name`),

KEY `ix_test` (`text`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 创建存储过程插入200万数据

CREATE PROCEDURE t5_insert_200w()

BEGIN

DECLARE i INT;

SET i=1000000;

WHILE i<=3000000 DO

INSERT INTO t5(`name`,text) VALUES('god-jiang666',concat('text', i));

SET i=i+1;

END WHILE;

END;

# 调用存储过程插入200万数据

call t5_insert_200w();

在翻页比较少的情况下,LIMIT是不会出现任何性能上的问题的。

但是如果用户需要查到最后面的页数呢?

通常情况下,我们要保证所有的页面可以正常跳转,因为不会使用order by xxx desc这样的倒序SQL来查询后面的页数,而是采用正序顺序来做分页查询:

select * from t5 order by text limit 100000, 10;

73b22209562edda340c085544ce8f0fe.png

采用这种SQL查询分页的话,从200万数据中取出这10行数据的代价是非常大的,需要先排序查出前1000010条记录,然后抛弃前面1000000条。我的macbook pro跑出来花了5.578秒。

接下来我们来看一下,上面这条SQL语句的执行计划:

explain select * from t5 order by text limit 1000000, 10;

a57b88672a6b44d8a963322c45544b5d.png

从执行计划可以看出,在大分页的情况下,MySQL没有走索引扫描,即使text字段我已经加上了索引。

这是为什么呢?

回到MySQL索引(二)如何设计索引中有提及到,MySQL数据库的查询优化器是采用了基于代价的,而查询代价的估算是基于CPU代价和IO代价。

如果MySQL在查询代价估算中,认为全表扫描方式比走索引扫描的方式效率更高的话,就会放弃索引,直接全表扫描。

这就是为什么在大分页的SQL查询中,明明给该字段加了索引,但是MySQL却走了全表扫描的原因。

然后我们继续用上面的查询SQL来验证我的猜想:

explain select * from t5 order by text limit 7774, 10;

6fa7f5496952ea16b608fe8d16cf8b26.png

explain select * from t5 order by text limit 7775, 10;

6f2fa8b1f516a15e24b2d68aacd9d607.png

以上的实验均在我的mbp上运行的,在7774这个临界点上,MySQL分别采用了索引扫描和全表扫描的查询优化方式。

所以可以认为MySQL会根据它自己的代价查询优化器来判断是否使用索引。

由于MySQL的查询优化器的算法核心是我们无法人工干预的,所以我们的优化思路就要着手于如何让分页维持在最佳的的分页临界点。

优化方式

1、使用覆盖索引

如果一条SQL语句,通过索引可以直接获取查询的结果,不再需要回表查询,就称这个索引为覆盖索引。

在MySQL数据库中使用explain关键字查看执行计划,如果extra这一列显示Using index,就表示这条SQL语句使用了覆盖索引。

让我们来对比一下使用了覆盖索引,性能会提升多少吧。

# 没有使用覆盖索引

select * from t5 order by text limit 1000000, 10;

963ba371e7c45ea77925d71c2be26e0c.png

2c3aa6528e9954dc5bcc8bb3dfbc2ef6.png

这次查询花了3.690秒,让我们看一下使用了覆盖索引优化会提升多少性能吧。

# 使用了覆盖索引

select id, `text` from t5 order by text limit 1000000, 10;

9e3b1b637feb7e155261cc2b4bc6781b.png

f72c7ea9be1fe26df7735f6b773786d4.png

从上面的对比中,超大分页查询中,使用了覆盖索引之后,花了0.201秒,而没有使用覆盖索引花了3.690秒,提高了18倍多,这在实际开发中,就是一个大的性能优化了。(该数据在我的mbp上运行得出)

2、子查询优化

因为实际开发中,用SELECT查询一两列操作是非常少的,因此上述的覆盖索引的适用范围就比较有限。

所以我们可以通过把分页的SQL语句改写成子查询的方法获得性能上的提升。

select * from t5 where id>=(select id from t5 order by text limit 1000000, 1) limit 10;

36e12ab40b61e08ce9a00862186f5a83.png

其实使用这种方法,提升的效率和上面使用了覆盖索引基本一致。

但是这种优化方法也有局限性:

这种写法,要求主键ID必须是连续的

Where子句不允许再添加其他条件

3、延迟关联

和上述的子查询做法类似,我们可以使用JOIN,先在索引列上完成分页操作,然后再回表获取所需要的列。

select a.* from t5 a inner join (select id from t5 order by text limit 1000000, 10) b on a.id=b.id;

e210992b1f3eb780947eccde90bff68f.png

从实验中可以得出,在采用JOIN改写后,上面的两个局限性都已经解除了,而且SQL的执行效率也没有损失。

4、记录上次查询结束的位置

和上面使用的方法都不同,记录上次结束位置优化思路是使用某种变量记录上一次数据的位置,下次分页时直接从这个变量的位置开始扫描,从而避免MySQL扫描大量的数据再抛弃的操作。

select * from t5 where id>=1000000 limit 10;

f0dd6a10ad580ee43021462e3e4febf8.png

根据以上实验,不难得出,由于使用了主键索引做分页操作,SQL的性能是最快的。

总结

介绍了超大分页查询性能过差的原因,还有分享了几个优化思路

超大分页的优化思路就是让分页的SQL尽量在最佳的性能区间执行,不要触发全表扫描即可

希望以上的分享,可以让你们在MySQL这条路上少走弯路~~~

参考资料

《MySQL性能优化》第六章 查询优化性能

《数据库查询优化器的艺术》

到此这篇关于MySQL优化教程之超大分页查询的文章就介绍到这了,更多相关MySQL超大分页查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/529554.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 分页 jdbc_JDBC调用MySQL分页存储过程实现(一)

DROP PROCEDURE IF EXISTS pro_pager;CREATE DEFINER root% PROCEDURE pro_pager(in p_pageNo int, /*当前页*/in p_perPageCnt int, /*每页记录数*/in p_sql VARCHAR(2000), /*查询sql语句*/out v_totalRowsCnt int, /*记录总条数*/out v_totalPageCnt int) /*记录总页数*/BE…

zabbix proxy mysql_zabbix proxy 配置

在监控大量服务器时&#xff0c;如果将所有的请求都发送到一个zabbix server上&#xff0c;将会对我们的zabbix server造成很大的压力&#xff0c;我们在规划多个区域或机房进行监控的时候&#xff0c;会考虑到使用zabbix proxy 来代理zabbix server 的部分功能。zabbix server…

mvc mysql linq_MVC3+Linq to sql 显示数据库中数据表的数据

1&#xff1a;首先创建asp.net mvc3应用程序 2&#xff1a;创建项目完成后 找到controllers文件鼠标右击选择添加控制器 3 为models文件夹添加一个linq to sql类文件&#xff0c;然后把数据库中的数据库复制进来。如截图操作 4&#xff1a;添加控制器好后会生成一个HomeControl…

mysql工作表格制作教程_Access制作复杂报表

何制作复杂报表利用excel输出复杂报表 在读这篇文章以前首先要提醒大家&#xff0c;Access 本身的报表也具有很强的实用性和强大的功能&#xff0c;只有当你发掘了其本身全部的功能却仍不能满足你对报表的特殊要求时才请使用 Excel 输出报表。很明显&#xff0c;使用 Excel 输出…

php+mysql投票代码_PHP+jQuery+MySql实现红蓝投票功能

本文是一篇综合知识应用类文章&#xff0c;需要您具备PHP、jQuery、MySQL以及html和css方面的基本知识。本文在《PHPMySqljQuery实现的“顶”和“踩”投票功能》一文基础上做了适当改进&#xff0c;共用了数据表&#xff0c;您可以先点击了解这篇文章。HTML我们需要在页面中展示…

numpy 最大值_第 85 天:NumPy 统计函数

数学统计在我们的程序当中特别是数据分析当中是必不可少的一部分&#xff0c;本文就来介绍一下 NumPy 常见的统计函数。最大值与最小值numpy.amin()用于计算数组中的元素沿指定轴的最小值。可以通过 axis 参数传入坐标轴来指定统计的轴&#xff0c;当指定 axis 时&#xff0c;a…

java中如何实现变量可配置_Java基础-如何配置环境变量

Java环境变量详细教程第一步、打开电脑环境变量设置窗口以Win10系统为例子。在桌面找到此电脑&#xff0c;右键此电脑— —>属性&#xff0c;点击属性— —>点击左侧高级系统设置点击高级系统设置点击环境变量第二步、新建JAVA_HOME点击系统变量中的新建,出现输入框&…

python三引号解析_[宜配屋]听图阁

和C语言一样&#xff0c;引号属于特殊功能字符&#xff0c;不能够像普通字符那样直接通过print打印&#xff0c;需要进行一些处理&#xff0c;比如说反斜杠转义等。这里介绍几种打印三引号的方法&#xff0c;希望对需要的朋友有用。1、第一中方法比较简单&#xff0c;直接使用三…

定时执行java程序_如何让Java程序定时运行

由于项目开发的需要&#xff0c;必须实现让一个Java程序定时运行。比如&#xff0c;我的项目中&#xff0c;有一个网络蜘蛛&#xff0c;需要从互联网上抓取数据&#xff0c;与其配合&#xff0c;有另一个程序来对新抓取的页面进行索引的创建&#xff0c;由于数据源更新频率不高…

卡法电子商务 java_javacard DES算法API使用示例

********** 2017年3月15日留言 ——关于java卡Applet系列csdn博文 *************貌似有不少人在看我写的几篇关于java卡applet的博文&#xff0c;也收到了一些评论指正博文错误&#xff0c;或者私信叫我发代码文件过去。在此需要说明的是&#xff0c;java卡applet的这几篇博文…

mysql dump工具升级_MySQL数据库升级

当前不少系统的数据库依旧是MySQL5.6&#xff0c;由于MySQL5.7及MySQL8.0在性能及安全方面有着很大的提升&#xff0c;因此需要升级数据库。本文通过逻辑方式、物理方式原地升级来介绍MySQL5.6 升级至MySQL5.7的方法&#xff0c;并介绍其使用场景。1. 逻辑方式升级逻辑方式升级…

java int 128 ==_为什么 Java Integer 中“128==128”为false,而”100==100“为true?

这是一个挺有意思的讨论话题&#xff0c;让我们用代码说话吧!运行下面的代码:Integer a 128, b 128;System.out.println(a b);Integer c 100, d 100;System.out.println(c d);你会得到:falsetrue基本知识&#xff1a;我们知道&#xff0c;如果两个引用指向同一个对象&…

初始java_第一章__初始JAVA

1.java的三个发展方向&#xff1a;JAVASE(面向对象、API、JVM)、JAVAME(移动设备、游戏、通信)、JAVAEE(JSP、EJB、服务)2.开发JAVA的程序步骤&#xff1a;1.编写源程序 2.编译 3.运行3.JDKJRE开发工具下载java环境jdk 安装并配置环境变量&#xff0c;.安装直接下一步下一步直到…

appium java环境_Appium环境搭建(Windows版)

注&#xff1a;appium安装到C盘&#xff0c;node.js安装到C盘一、安装node.js1、到官网下载node.js&#xff1a;https://nodejs.org/en/download/2、获取到安装文件后&#xff0c;直接双击安装文件&#xff0c;根据程序的提示&#xff0c;完成nodejs的安装。3、安装完成后&…

ie11加载java插件_IE浏览器中ActiveX插件的使用

在某些行业的B/S应用系统中会不可避免的要用到ActiveX浏览器插件&#xff0c;而ActiveX插件只能在IE内核浏览器中运行&#xff0c;而常用的IE浏览器的版本众多&#xff0c;从IE6到IE11&#xff0c;总共有6个版本&#xff0c;这就给开发的应用系统造成了不小的困扰&#xff1a;如…

mysql的增_MySQL之增_insert-replace

MySQL增删改查之增insert、replace一、INSERT语句带有values子句的insert语句&#xff0c;用于数据的增加语法&#xff1a;INSERT [INTO] tbl_name[(col_name,...)]{VALUES | VALUE} (expr ,...),(...),...①用来把一个新行插入到表中②为和其它数据库保持一致&#xff0c;不要…

php redis 传递闭包,通过缓存构建高性能 Laravel 应用

通过缓存构建高性能 Laravel 应用由 学院君 创建于3年前, 最后更新于 11个月前版本号 #220678 views9 likes1 collects配置Laravel 为不同的缓存系统提供了统一的 API。缓存配置位于 config/cache.php。在该文件中你可以指定在应用中默认使用哪个缓存驱动。Laravel 开箱支持主流…

imclearboder matlab,Lucas

Lucas-Kanade跟踪算法是视觉跟踪中一个很经典的基于点的逐帧跟踪算法。起初这个算法是用来求解stero matching1的&#xff0c;后来经过Carlo Tomasi2和Jianbo Shi3等人的发展渐趋成熟。Jianbo Shi提出了一种筛选跟踪点特征的方法&#xff0c;使得特征的跟踪更可靠。Jean-Yves B…

matlab求勒让德多项式零点,有没有勒让德多项式导数 零点程序

求N1次勒让德多项式的m(m0,1,...)阶导数零点Matlab程序子程序&#xff1a;function xjp(N,alpha,beta)n1:N;a(1)(alphabeta2)/2;b(1)(beta-alpha)/2;a([2:N1])(2*nalphabeta1).*(2*nalphabeta2)./(2*(n1).*(nalphabeta1));b([2:N1])(alpha*alpha-beta*beta)*(2*nalphabeta1)./(…

js_long.php,protobuf.js 与 Long.js的使用详解

这次给大家带来protobuf.js 与 Long.js的使用详解&#xff0c;是急用protobuf.js 与 Long.js的注意事项有哪些&#xff0c;下面就是实战案例&#xff0c;一起来看一下。protobuf.js的结构和webpack的加载之后的结构很相似。这样的模块化组合是个不错的结构方式。1个是适应了不同…