ThinkPHP 5.1 优化 MySQL 深分页(Deep Paging)查询【Limit】

落芳酱_1047

落芳酱_1047

2026-07-09

830人浏览

原创

thinkphp 5.1 十万级数据分页变慢的根本原因是 mysql 的 limit offset, size 导致全表扫描前 offset 行;解决方案包括关闭 totalcount、使用 simple 分页、添加复合索引 (user_id, create_time)、确保字段 not null,并改用基于 id 的游标分页替代 offset 分页。

thinkphp 5.1 优化 mysql 深分页(deep paging)查询【limit】

ThinkPHP 5.1 应用在数据量超过十万级后,用户翻到第200页、第500页时页面加载明显变慢,甚至超时,根本原因是 MySQL 执行 LIMIT 9990, 20 类查询时被迫扫描并丢弃前9990行——这不是 PHP 层能绕开的数据库底层瓶颈。

关闭 totalCount 统计跳过 COUNT(*) 全表扫描

默认 paginate() 会执行两条 SQL:一条 SELECT COUNT(*) 算总数,一条 SELECT LIMIT 取数据。COUNT(*) 在无索引或大表上可能耗时数百毫秒甚至秒级。

第一步:在控制器中调用 paginate 时,将第二个参数设为 false:

$list = Db::name('order')->where('user_id', $uid)->paginate(20, false);

第二步:视图中渲染分页 HTML 时,改用 simple 模式避免依赖总页数:

{$list->simple()->render()}

第三步:若需保留搜索参数(如 ?keyword=abc&page=3),必须显式追加:

{$list->simple()->appends(request()->param())->render()}

这一步不补 appends,翻页后所有 GET 参数都会丢失,搜索结果无法持续。

用联合索引让 WHERE + ORDER 快速定位起始行

即使关掉 COUNT,如果 LIMIT 起始位置无法通过索引直接跳转,MySQL 仍要从头扫描。关键不是“有没有索引”,而是“索引是否覆盖 WHERE 条件 + ORDER BY 字段”。

方法一:检查当前查询是否走索引

执行 EXPLAIN SELECT * FROM order WHERE user_id = 123 ORDER BY create_time DESC LIMIT 20;,确认 【type 不是 ALL,key 显示实际索引名】。

方法二:建复合索引,顺序必须严格匹配查询逻辑

WHERE 先过滤 user_id,再按 create_time 倒序排列,索引字段顺序就得是 (user_id, create_time):

ALTER TABLE `order` ADD INDEX idx_uid_ctime (user_id, create_time DESC);

注意:MySQL 8.0+ 支持降序索引,5.7 及以下版本会忽略 DESC,但依然能用该索引加速 ORDER BY。

方法三:强制 NOT NULL 并验证字段可索引性

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载

如果 create_time 允许 NULL,MySQL 可能放弃使用该索引。执行 ALTER TABLE `order` MODIFY COLUMN create_time DATETIME NOT NULL; 再重建索引。

替换 offset 分页为游标分页(Cursor-based)

当用户滑动到第 1000 页以上,offset 分页已不可逆地成为性能毒药。游标分页不依赖页码,只依赖上一页最后一条记录的锚点值,彻底避开 OFFSET 扫描。

方法1:基于自增主键 id 的区间查询(最稳定)

首次请求:取最新20条 → SELECT * FROM order WHERE user_id = 123 ORDER BY id DESC LIMIT 20;

下一页请求:带上上一页最小 id(假设为 8842)→ SELECT * FROM order WHERE user_id = 123 AND id

方法2:基于时间戳 + 主键防重复(适用于 create_time 可能重复场景)

首次请求:取最新20条 → SELECT id, user_id, create_time, title FROM order WHERE user_id = 123 ORDER BY create_time DESC, id DESC LIMIT 20;

下一页请求:带上上一页最后一条的 (create_time, id) 作为边界 → SELECT ... WHERE user_id = 123 AND (create_time, id)

这一步必须用 【ORDER BY create_time DESC, id DESC】双字段排序】,否则时间相同的数据会乱序,导致漏查或重复。

方法3:在 ThinkPHP 5.1 中封装游标逻辑(不依赖 paginate)

控制器中手动构造查询:

$last_id = input('last_id/d', 0);

$map = ['user_id' => $uid];

if ($last_id > 0) { $map['id'] = ['

$list = Db::name('order')->where($map)->order('id DESC')->limit(20)->select();

前端分页链接传参只需 ?last_id=8842,无需 page 参数,URL 更干净,也杜绝了恶意传入极大 page 值触发深 offset 查询。

php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!

灵契少女相关攻略
《灵契少女》阴间宝箱获取攻略 《灵契少女》第一章生命之树探索攻略 《灵契少女》拉卡镇全宝箱收集攻略
《灵契少女》静寂林地全宝箱收集攻略 揭秘《灵契少女》中的冰魄秘剑 《灵契少女》幽光果分布位置一览
《灵契少女》肿胀之心技能效果分享 sql中%的含义 快速掌握sql中%的作用 mysql中%的用法 mysql通配符%使用场景
如何在PostgreSQL中使用OFFSET实现SQL分页查询功能? 如何在MySQL中利用UNION运算符合并两个SQL查询结果? 为什么MySQL在执行UNION操作时性能远低于UNION ALL?
如何在SQL中实现类似于Excel的分类汇总功能? 如何解决MySQL中GROUP BY查询结果与预期不符的问题? 如何在SQL中实现对非数值类型字段的自定义规则聚合?
MySQL中UNION与UNION ALL区别 如何在SQL中利用GROUP BY和HAVING子句过滤聚合后的数据? 如何利用SQL聚合函数快速查找表中的重复记录?
如何使用SQL聚合结果作为子查询的过滤条件? SQL如何实现对分组后的数据进行二次筛选与排序? 如何使用SQL聚合函数统计异常日志的出现频率?
为什么MySQL在执行Union操作时如果不加All会产生额外的索引压力? SQL中如何使用HAVING过滤GROUP BY的分组结果? 如何在SQL中使用分组函数进行数据清洗?
如何在SQL嵌套查询中使用集合运算符(Union/Intersect)进行过滤? 如何在PostgreSQL中使用复杂聚合函数进行分组? 为什么在SQL查询中聚合函数不能直接出现在WHERE子句里?
SQL分组查询中HAVING与WHERE有什么本质区别? 如何通过限制查询返回行数减轻SQL注入危害? 为什么Navicat 15在生成ER图时无法显示字段的完整描述信息?

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

thinkphp mysql php

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

1933

6

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.21

1199

5

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

695

5

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.19

2532

5

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.25

4148

4

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.08

979

3

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.11

4431

4

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

2023.08.14

4002

7

mysql事务隔离级别
mysql事务隔离级别

mysql规范中定义了四种事务隔离级别,不同的隔离级别对事务的处理有所不同。本专题为大家提供mysql事务隔离级别相关的文章内容,大家可以免费体验。

2023.08.16

5154

11

热门下载

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

精品课程

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