分页接口需要解决的核心问题
列表接口直接返回全表数据,在数据量增长后会带来响应体过大、查询变慢、前端渲染卡顿等问题。分页的本质是把一次全量读取拆成多次定量读取,接口需要明确三件事:取第几页、每页多少条、总共有多少条。围绕这三点,PHP 侧的实现可以拆成参数接收、参数校验、偏移量计算、数据库查询、结果组装五个步骤。
参数接收与校验
客户端通常通过 page 和 pageSize 两个查询参数控制分页。接收后必须做类型转换与边界限制,否则会出现负数偏移、超大分页拖垮数据库等问题。
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$pageSize = isset($_GET['pageSize']) ? (int)$_GET['pageSize'] : 10;
// 边界处理
$page = max(1, $page);
$pageSize = min(max(1, $pageSize), 100); // 单页上限建议 50~100
校验要点:
page最小为 1,小于 1 时归一到 1,避免出现负偏移量pageSize设置上限,防止客户端传入pageSize=100000造成慢查询- 强制转为整型,过滤
1abc、1.5这类非法输入 - 若接口有固定业务场景,可对
pageSize提供白名单(如 10/20/50)
偏移量计算与 SQL 查询
偏移量公式为 offset = (page - 1) * pageSize。注意 LIMIT 的两个参数顺序是「偏移量, 条数」,写反是常见错误。
$offset = ($page - 1) * $pageSize;
// 使用 PDO 预处理,LIMIT 参数需绑定为整数
$stmt = $pdo->prepare(
'SELECT id, title, created_at FROM articles ORDER BY id DESC LIMIT :offset, :limit'
);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->bindValue(':limit', $pageSize, PDO::PARAM_INT);
$stmt->execute();
$list = $stmt->fetchAll(PDO::FETCH_ASSOC);
两个实践细节:
LIMIT占位符必须用PDO::PARAM_INT绑定,字符串绑定在部分驱动下会报语法错误- 排序字段要有索引,
ORDER BY id DESC配合主键可避免额外排序开销
总条数查询与响应结构
前端做页码导航需要总条数,因此要额外执行一次 COUNT(*)。两次查询条件应保持一致,否则会出现「总数与列表对不上」的问题。
$countStmt = $pdo->prepare('SELECT COUNT(*) FROM articles');
$countStmt->execute();
$total = (int)$countStmt->fetchColumn();
$totalPages = (int)ceil($total / $pageSize);
echo json_encode([
'code' => 0,
'data' => [
'list' => $list,
'page' => $page,
'pageSize' => $pageSize,
'total' => $total,
'totalPages' => $totalPages,
],
], JSON_UNESCAPED_UNICODE);
响应字段建议固定为 list / page / pageSize / total / totalPages,前端只需按约定取值,不必每次适配新结构。
边界与性能注意事项
| 场景 | 处理方式 |
|---|---|
| 页码超出总页数 | list 返回空数组,total 照常返回,不报错 |
| 总数为 0 | totalPages 返回 0,前端隐藏分页组件 |
| 深分页(如第 10000 页) | 大偏移量扫描成本高,可改用游标分页(WHERE id < lastId) |
| 数据频繁增删 | 翻页过程中总数可能变化,属正常现象,无需强一致 |
| 高并发列表 | 对 COUNT(*) 结果做短时缓存,降低数据库压力 |
可执行结论
实现一个可用的分页接口,最小闭环是:接收并强制转换 page、pageSize → 限制取值范围 → 计算 offset → 用预处理语句执行带 LIMIT 的查询 → 单独查询总数 → 按统一结构返回。数据量不大时这套方案足够;当单表数据达到百万级且存在深分页需求时,再评估游标分页或基于索引的优化方案。
© 版权声明
文章版权归作者所有,未经允许请勿转载。