← 中文资源

简体中文版本

键集分页 Seek 方法

用复合游标实现键集分页:元组比较条件让索引直接定位下一页起点,深页性能不衰减,与 OFFSET 方案形成鲜明对照。

阅读英文原文

示例说明

OFFSET 十万意味着数据库要扫过并丢弃十万行才返回二十行——页码越深代价线性增长。键集分页把锚点写进 WHERE:复合元组比较直接在索引上定位起点,二十行即取即回,第一页与第一万页同价。元组比较语义等价于 OR 组合的两组条件但更简洁。

技术要点

  • 元组比较替代 OR 组合更简洁
  • 深页与首页同价不受页码影响
  • 索引排序方向与查询严格一致

代码解读

第一条查询的 WHERE 元组比较等价于时间早于锚点或时间相同但 ID 小——复合索引按相同方向组织,B 树定位一次即得;对照的 OFFSET 版本演示代价陷阱。首页请求只是无 WHERE 的退化形态。末尾的 EXPLAIN ANALYZE 供实际对比两种计划的 rows 与执行时间。

使用建议

游标对客户端保持不透明(编码或加密)。排序键必须唯一否则分页会重漏行。前端无限滚动天然契合此模式,页码跳转需换方案。

代码示例

-- 键集分页:锚点条件让索引直接定位下一页
SELECT id, created_at, title
FROM articles
WHERE (created_at, id) < ('2026-10-21 14:30:00', 98765)
ORDER BY created_at DESC, id DESC
LIMIT 20;

-- 对照的 OFFSET 版本:深页要扫过全部前序行
SELECT id, created_at, title
FROM articles
ORDER BY created_at DESC, id DESC
LIMIT 20 OFFSET 100000;

-- 首页请求(无锚点)
SELECT id, created_at, title
FROM articles
ORDER BY created_at DESC, id DESC
LIMIT 20;

-- 配套复合索引:排序方向与查询一致
CREATE INDEX idx_articles_page
  ON articles (created_at DESC, id DESC);

-- 验证两种方案的代价差异
EXPLAIN ANALYZE
SELECT id FROM articles
WHERE (created_at, id) < ('2026-10-21 14:30:00', 98765)
ORDER BY created_at DESC, id DESC LIMIT 20;