0

0

mysql分页查询怎么优化

青灯夜游

青灯夜游

发布时间:2022-06-20 13:09:10

|

3767人浏览过

|

来源于php中文网

原创

分页查询的优化方式:1、子查询优化,可通过把分页的SQL语句改写成子查询的方法获得性能上的提升。2、id限定优化,可以根据查询的页数和查询的记录数计算出查询的id的范围,然后根据“id between and”语句来查询。3、基于索引再排序进行优化,通过索引去找相关的数据地址,避免全表扫描。4、延迟关联优化,可以使用JOIN,先在索引列上完成分页操作,然后再回表获取所需要的列。

mysql分页查询怎么优化

本教程操作环境:windows7系统、mysql8版本、Dell G3电脑。

分页查询的效率在数据量大的时候尤为重要,影响到前端响应和用户体验。

分页查询的优化方式

1、使用子查询优化

这种方式先定位偏移位置的 id,然后往后查询,这种方式适用于 id 递增的情况。

子查询优化原理:https://www.jianshu.com/p/0768ebc4e28d

select * from sbtest1 where k=504878 limit 100000,5;的查询过程:

首先会查询到索引叶子节点数据,然后根据叶子节点上的主键值去聚簇索引上查询需要的全部字段值。像下图左边这样,需要查询100005次索引节点,查询100005次聚簇索引的数据,最后再将结果过滤掉前100000条,取出最后5条。MySQL耗费了大量随机I/O在查询聚簇索引的数据上,而有100000次随机I/O查询到的数据是不会出现在结果集当中的。

在这里插入图片描述

既然一开始是利用索引的,为什么不先沿着索引叶子节点查询到最后需要的5个节点,然后再去聚簇索引中查询实际数据。这样只需要5次随机I/O,类似于上图右边的过程。这就是子查询优化,这种方式先定位偏移位置的id,然后往后查询,这种方式适用于id递增的情况。如下所示:

mysql> select *  from sbtest1 where k=5020952 limit 50,1;
mysql> select id  from sbtest1 where k=5020952 limit 50,1;
mysql> select * from sbtest1 where k=5020952 and id>=( select id  from sbtest1 where k=5020952 limit 50,1) limit 10;
mysql> select * from sbtest1 where k=5020952 limit 50,10;

在子查询优化中,谓词中k是否有索引,对查询效率有很大影响,上述语句没有使用索引走全表扫描需要24.2s,走了索引后只需要0.67s。

mysql> explain  select * from sbtest1 where k=5020952 and id>=( select id  from sbtest1 where k=5020952 limit 50,1) limit 10;
+----+-------------+---------+------------+-------------+---------------+------------+---------+-------+------+----------+------------------------------------------+
| id | select_type | table   | partitions | type        | possible_keys | key        | key_len | ref   | rows | filtered | Extra                                    |
+----+-------------+---------+------------+-------------+---------------+------------+---------+-------+------+----------+------------------------------------------+
|  1 | PRIMARY     | sbtest1 | NULL       | index_merge | PRIMARY,c1    | c1,PRIMARY | 8,4     | NULL  |   19 |   100.00 | Using intersect(c1,PRIMARY); Using where |
|  2 | SUBQUERY    | sbtest1 | NULL       | ref         | c1            | c1         | 4       | const |   88 |   100.00 | Using index                              |
+----+-------------+---------+------------+-------------+---------------+------------+---------+-------+------+----------+------------------------------------------+
2 rows in set, 1 warning (0.11 sec)

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

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

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

2、使用id限定优化

这种方式假设数据表的id是连续递增的,则我们根据查询的页数和查询的记录数可以算出查询的id的范围,可以使用 id between and 来查询。

假设数据库中表的id是连续递增的,则可以根据查询的页数和查询的记录数计算出查询的id的范围,然后根据id between and语句来查询。id的范围可以通过分页公式计算得到,比如说当前页面大小为m,当前页数为no1,则页面最大值为max=(no1+1)m-1,最小值为min=no1m,SQL语句可以表示为id between min and max。

select * from sbtest1 where id between 1000000 and 1000100 limit 100;

这种查询方式能够极大地优化查询速度,基本能够在几十毫秒之内完成。限制是需要明确知道id的情况,不过一般在分页查询的业务表中,都会添加基本的id字段,这为分页查询带来很多便利。上述SQL还有另一种写法:

select * from sbtest1 where id >= 1000001 limit 100;

可以看到执行时间上的差异:

MediPro网上书店系统
MediPro网上书店系统

基于PHP+MYSQL开发,除了网上书店必备的商品管理、配送支付管理、订单管理、会员分组、会员管理、查询统计和多项商品促销功能,还具有完整的文章、图文、下载、单页、广告发布等网站内容管理功能。系统具有静态HTML生成、UTF-8多语言支持、可视化模版引擎等技术特点,支持多频道调用不同模版和任意设置频道首页,适合建立各种规模的网上书店。系统具有以下主要功能模块: 网站参数设置 - 对网站的一些参数进

下载
mysql> show profiles;
+----------+------------+--------------------------------------------------------------------------------------------------------------+
| Query_ID | Duration   | Query                                                                                                        |
+----------+------------+--------------------------------------------------------------------------------------------------------------+
|        6 | 0.00085500 | select * from sbtest1 where id between 1000000 and 1000100 limit 100                                         |
|        7 | 0.12927975 | select * from sbtest1 where id >= 1000001 limit 100                                                          |
+----------+------------+--------------------------------------------------------------------------------------------------------------+

还可以使用in的方式来进行查询,这种方式经常用在多表关联的时候进行查询,使用其他表查询的id集合,来进行查询:

select * from sbtest1 where id in (select id from sbtest2 where k=504878) limit 100;

使用in查询的方式要注意某些mysql版本不支持在in子句中使用limit。

3、基于索引再排序来优化

基于索引再排序是利用索引查询中有优化算法,通过索引再去找相关的数据地址,避免全表扫描,这样节省了很多时间。另外Mysql中也有相关的索引缓存,在并发高的时候利用缓存效果会更好。在MySQL中可以使用如下语句:

SELECT * FROM 表名称 WHERE id_pk > (pageNum*10) ORDER BY id_pk ASC LIMIT M

这种方法适用于数据量多的情况(元组数上万),最好ORDER BY后的列对象是主键或唯一索引,使得ORDER BY操作能利用索引被消除但结果集是稳定的。比如下面两个语句:

mysql> show profiles;
+----------+------------+--------------------------------------------------------------------------------------------------------------+
| Query_ID | Duration   | Query                                                                                                        |
+----------+------------+--------------------------------------------------------------------------------------------------------------+
|        8 | 3.30585150 | select * from sbtest1 limit 1000000,10                                                                       |
|        9 | 1.03224725 | select * from sbtest1 order by id limit 1000000,10                                                           |
+----------+------------+--------------------------------------------------------------------------------------------------------------+

对索引字段id使用order by语句后,性能有了明显的提升。

4、使用延迟关联来优化

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

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

4.png

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

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

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

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

5.png

6、使用临时表优化

使用临时存储的表来记录分页的id然后进行in查询

这种方式已经不属于查询优化,这儿附带提一下。

对于使用 id 限定优化中的问题,需要 id 是连续递增的,但是在一些场景下,比如使用历史表的时候,或者出现过数据缺失问题时,可以考虑使用临时存储的表来记录分页的id,使用分页的id来进行 in 查询。这样能够极大的提高传统的分页查询速度,尤其是数据量上千万的时候。

【相关推荐:mysql视频教程

相关专题

更多
Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

34

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

14

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

33

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

18

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

12

2026.01.13

PHP缓存策略教程大全
PHP缓存策略教程大全

本专题整合了PHP缓存相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.13

jQuery 正则表达式相关教程
jQuery 正则表达式相关教程

本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

3

2026.01.13

交互式图表和动态图表教程汇总
交互式图表和动态图表教程汇总

本专题整合了交互式图表和动态图表的相关内容,阅读专题下面的文章了解更多详细内容。

44

2026.01.13

nginx配置文件详细教程
nginx配置文件详细教程

本专题整合了nginx配置文件相关教程详细汇总,阅读专题下面的文章了解更多详细内容。

5

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 1.7万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 791人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号