php查询数据怎么分页查_limit分页公式及用法【详解】

发布时间 - 2026-01-02 00:00:00    点击率:
LIMIT offset, length 是最常用写法,但 offset 偏移量大时性能骤降,且排序字段不唯一会导致漏行或重复;应优先考虑游标分页,并严格校验分页参数。

MySQL 的 LIMIT 分页语法怎么写才不跳数据

直接说结论:LIMIT offset, length 是最常用写法,但 offset 偏移量变大时性能会明显下降,且在有重复排序字段(比如时间相同)时容易漏行或重复。不是所有分页都适合用它。

典型错误是这样写:SELECT * FROM user ORDER BY id LIMIT 10000, 20 —— 当 offset 超过几万,MySQL 要先扫描前 10020 行再丢弃前 10000 行,IO 和 CPU 开销陡增。

  • offset 为 0 时最快,越往后越慢
  • 如果 ORDER BY 字段不唯一(如多个记录 created_at 相同),LIMIT 无法保证稳定顺序,翻页可能看到重复或丢失数据
  • PHP 中拼接 SQL 时,务必对 $page$pageSize 做整型校验,否则易被注入或报错

PHP 中计算 offset 的安全公式

分页本质是算出从第几条开始取,公式就是:offset = ($page - 1) * $pageSize。注意:页码必须从 1 开始,不能从 0;$page 必须是正整数,$pageSize 通常限制在 1–100 之间。

常见疏漏:

立即学习“PHP免费学习笔记(深入)”;

  • 没做 max(1, (int)$page) 校验,传入负数或字符串导致 offset 为 0 或负值,MySQL 报错 Invalid argument
  • 没限制 $pageSize 上限,攻击者传 ?limit=1000000 可能拖垮数据库
  • 没统一处理空参,默认值设在 SQL 层(如 IFNULL)不如在 PHP 层早拦住
php
$page = max(1, (int)($_GET['page'] ?? 1));
$pageSize = max(1, min(100, (int)($_GET['limit'] ?? 20)));
$offset = ($page - 1) * $pageSize;

$stmt = $pdo->prepare("SELECT id, name FROM user ORDER BY id ASC LIMIT :offset, :length"); $stmt->bindValue(':offset', $offset, PDO::PARAM_INT); $stmt->bindValue(':length', $pageSize, PDO::PARAM_INT); $stmt->execute();

什么时候该换 Cursor 分页代替 LIMIT

当列表需按时间倒序、且数据高频写入(如消息流、日志),用 LIMIT offset, length 会越来越卡,还可能因新插入数据导致“上一页末尾”和“下一页开头”之间出现断层或重复。这时应改用基于游标的分页(Cursor-based Pagination)。

核心思路:不依赖行号,而用上一页最后一条的排序字段值作为下一页起点。

  • 要求排序字段(如 idcreated_at)必须有索引,且尽量唯一
  • 首次请求不带 cursor,后续请求传上一页最后一条的 id(比如 ?cursor=12345
  • SQL 改为:WHERE id ,避免 OFFSET
  • PHP 中需确保 cursor 是合法整型,且大于 0,否则拒绝查询
php
$cursor = (int)($_GET['cursor'] ?? 0);
if ($cursor > 0) {
    $stmt = $pdo->prepare("SELECT id, title FROM article WHERE id < ? ORDER BY id DESC LIMIT 20");
    $stmt->execute([$cursor]);
} else {
    $stmt = $pdo->prepare("SELECT id, title FROM article ORDER BY id DESC LIMIT 20");
    $stmt->execute();
}

count(*) 分页总数要不要查

查总数(SELECT COUNT(*))看起来直观,但对大表是性能杀手。尤其当只展示「下一页」按钮、不显示总页数时,完全没必要查。

更务实的做法:

  • 只查一页数据(比如 20 条),然后判断是否查到了满额(20 条)。如果不到 20 条,说明已是最后一页
  • 需要总数时,用近似值:SHOW TABLE STATUS LIKE 'user'Rows 字段(MyISAM 准确,InnoDB 是估算)
  • 或者加缓存:总数变化不频繁时,用 Redis 缓存 user:count,定时或写操作后更新
  • 绝对避免在分页接口里每次执行 SELECT COUNT(*) FROM ... WHERE ... ORDER BY ...,WHERE 条件复杂时可能比主查询还慢

游标分页天然不依赖总数,所以也绕开了这个问题。


# mysql  # php  # redis  # red  # sql  # count  # select  # 整型  # 字符串  # int  # 接口  # Length  # table  # 数据库  # 分页  # 下一页  # 上一页  # 行号  # 报错  # 最常用  # 不依赖  # 首次  # 多个 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Windows10怎样连接蓝牙设备_Windows10蓝牙连接步骤【教程】  清除minerd进程的简单方法  教你用AI将一段旋律扩展成一首完整的曲子  高端建站三要素:定制模板、企业官网与响应式设计优化  英语简历制作免费网站推荐,如何将简历翻译成英文?  如何快速生成专业多端适配建站电话?  如何在腾讯云服务器上快速搭建个人网站?  Laravel Facade的原理是什么_深入理解Laravel门面及其工作机制  高端云建站费用究竟需要多少预算?  武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  宙斯浏览器怎么屏蔽图片浏览 节省手机流量使用设置方法  如何在服务器上配置二级域名建站?  Windows Hello人脸识别突然无法使用  Laravel怎么解决跨域问题_Laravel配置CORS跨域访问  HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】  常州企业网站制作公司,全国继续教育网怎么登录?  Laravel Session怎么存储_Laravel Session驱动配置详解  php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】  Laravel如何使用模型观察者?(Observer代码示例)  UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  WordPress 子目录安装中正确处理脚本路径的完整指南  如何用PHP快速搭建高效网站?分步指南  美食网站链接制作教程视频,哪个教做美食的网站比较专业点?  黑客如何利用漏洞与弱口令入侵网站服务器?  如何快速选择适合个人网站的云服务器配置?  小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?  linux写shell需要注意的问题(必看)  大同网页,大同瑞慈医院官网?  打开php文件提示内存不足_怎么调整php内存限制【解决方案】  Laravel PHP版本要求一览_Laravel各版本环境要求对照  使用豆包 AI 辅助进行简单网页 HTML 结构设计  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  Laravel怎么连接多个数据库_Laravel多数据库连接配置  ChatGPT 4.0官网入口地址 ChatGPT在线体验官网  Laravel如何实现数据库事务?(DB Facade示例)  Laravel如何发送系统通知?(Notification渠道示例)  高端智能建站公司优选:品牌定制与SEO优化一站式服务  如何在建站宝盒中设置产品搜索功能?  Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】  如何用虚拟主机快速搭建网站?详细步骤解析  Laravel如何与Pusher实现实时通信?(WebSocket示例)  QQ浏览器网页版登录入口 个人中心在线进入  Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】  Laravel队列任务超时怎么办_Laravel Queue Timeout设置详解  手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?  深圳防火门网站制作公司,深圳中天明防火门怎么编码?  Linux系统命令中screen命令详解  Laravel如何实现多对多模型关联?(Eloquent教程)