Skip to content

分页查询重复与遗漏 ​

问题现象 ​

翻页时同一条数据出现两次,或某条记录始终看不到;同一个 SQL 多次运行顺序不同。

适用环境 ​

MySQL 8、MyBatis;排序字段可能重复,列表持续有写入。

本文是可复用的排障示例,不代表某次个人生产事故。命令中的名称、账号和数据均为示例,执行前请替换为已确认的目标。

复现或诊断步骤 ​

  1. 检查 ORDER BY 是否有唯一末级排序键。
  2. 固定数据集重复执行,区分排序不稳定与并发插入造成的偏移变化。
  3. 核对一对多 JOIN 是否先放大了行数,再被分页;比较 count 查询与数据查询的条件。

原因分析 ​

只按 created_at 排序时,同一时间的记录没有确定顺序。OFFSET 分页遇到新增或删除会整体移动位置。先 JOIN 再分页也可能把同一业务实体拆到多页。

修复示例 ​

sql
-- 第一页
SELECT id, created_at, title
FROM article
ORDER BY created_at DESC, id DESC
LIMIT 20;

-- 下一页携带上一页末行的两个排序值
SELECT id, created_at, title
FROM article
WHERE created_at < :cursor_time
   OR (created_at = :cursor_time AND id < :cursor_id)
ORDER BY created_at DESC, id DESC
LIMIT 20;

建立与过滤和排序匹配的组合索引,游标必须包含完整排序值。涉及多个关联表时,先确定主实体 ID 页,再加载关联数据。需要报表级一致结果时采用明确快照或导出任务,游标本身不能冻结被修改的排序字段。

验证方法 ​

准备同一时间的多条记录,遍历所有页核对 ID 集合。翻页期间插入新记录、删除旧记录并记录所选一致性语义;测试 cursor 参数校验与时间精度。

常见误区 ​

DISTINCT 并非万能修复,可能改变统计和性能。稳定 ORDER BY 可以解决静态数据排序,不能保证 OFFSET 在并发写入下无遗漏。

官方参考链接 ​

相关分类:Java 后端 · 全部笔记