⭐ 推荐:社区规则条款 V1.0

数据库分页查询越翻越慢,游标分页到底该怎么实现?

GJ
GJ 资深会员 👑黑卡会员
发布于 2026-11-03 14:28 ·3 浏览 ·0 回复

学完这篇,你将掌握如何通过“游标分页”技术替代传统的“OFFSET分页”,解决大数据量下翻页性能急剧下降的问题。

为什么 OFFSET 分页会越翻越慢?

在开始实现游标分页之前,必须先理解传统分页的痛点。传统的分页查询通常使用 LIMIT offset, size。例如查询第 100 页,SQL 可能是 SELECT * FROM articles LIMIT 100, 10。

数据库执行这个语句时,必须先扫描前 100 行数据,然后丢弃这 100 行,再返回接下来的 10 行。随着你翻页越往后,数据库需要扫描并丢弃的数据量就越大,查询耗时呈线性增长,这就是“越翻越慢”的根本原因。

什么是游标分页?

游标分页的核心思想是:利用上一条记录的唯一标识(通常是 ID)作为下一页查询的起点。通过 WHERE id > last_id 的条件,数据库不需要扫描前面的数据,直接从指定位置开始读取。这种方式无论翻到第几页,查询耗时基本恒定。

第一步:确保 ID 索引建立(性能基石)

这一步要做什么、做完得到什么结果:在执行游标分页前,必须确保用于排序和筛选的 ID 字段已经建立了索引,否则查询性能提升有限。

具体操作:

  1. 打开你的数据库客户端(如 Navicat、DBeaver 或 MySQL 命令行)。
  2. 找到对应的数据库表。
  3. 执行建表语句或添加索引的 SQL 命令。假设表名为 user_logs,主键为 id。

注意:如果表中已有大量数据,添加索引可能需要较长时间,请选择业务低峰期执行。

SQL 命令示例:

-- 为 id 字段添加索引(假设 id 是主键,通常自带索引,这里演示手动添加)
CREATE INDEX idx_id ON user_logs(id);

第二步:获取第一页数据(基准查询)

这一步要做什么、做完得到什么结果:执行标准的 LIMIT 查询获取第一页数据,并记录下最后一条记录的 ID,作为下一页的“游标”。

具体操作:

  1. 执行 SQL 语句,通常按 ID 降序排列,因为最新的数据通常排在前面。
  2. 获取结果集后,不要只取数据,要提取最后一条数据的 id。

SQL 命令示例:

-- 获取第一页,每页 10 条
SELECT id, title, content 
FROM user_logs 
ORDER BY id DESC 
LIMIT 10;

假设查询结果最后一条记录的 id 是 500,那么 500 就是当前的游标。

第三步:实现下一页查询(核心逻辑)

这一步要做什么、做完得到什么结果:利用上一步记录的 ID,使用 WHERE id < last_id 配合 ORDER BY 和 LIMIT,实现快速翻页。

具体操作:

  1. 将第二步得到的 last_id 代入 SQL 查询。
  2. 使用 < 而不是 >,因为我们默认是按 ID 降序排列(从大到小),要找更早的记录。

SQL 命令示例:

-- 获取上一页(即当前页的上一页),游标为 500
SELECT id, title, content 
FROM user_logs 
WHERE id < 500 
ORDER BY id DESC 
LIMIT 10;

数据库会直接定位到 ID 小于 500 的位置,读取 10 条,无需扫描前面的数据。

第四步:处理排序与特殊情况(边界情况)

这一步要做什么、做完得到什么结果:解决当 ID 不连续、或者需要按多字段排序时的实现方案。

具体操作:

  1. ID 不连续:游标分页不要求 ID 连续。只要 ID 是唯一的且有序的,WHERE id < last_id 都能正确工作。
  2. 多字段排序:如果排序条件不仅仅是 ID,而是 ORDER BY create_time DESC, id DESC,那么游标分页需要同时锁定这两列。

注意:多字段排序时,游标必须包含所有排序字段。例如 WHERE create_time < '2023-01-01' AND id < 500。

SQL 命令示例(多字段排序):

SELECT id, title, content 
FROM user_logs 
ORDER BY create_time DESC, id DESC 
LIMIT 10;

对应的下一页查询:

SELECT id, title, content 
FROM user_logs 
WHERE (create_time < '2023-01-01' AND id < 500) 
ORDER BY create_time DESC, id DESC 
LIMIT 10;

小结

  1. 传统分页慢:OFFSET 导致数据库扫描大量无用数据,越往后越慢。
  2. 游标分页快:利用上一条记录的 ID 作为查询条件(WHERE id < last_id),实现跳跃式读取。
  3. 必须建索引:确保 ID 字段有索引,这是性能提升的关键。
  4. 注意排序:多字段排序时,游标条件必须包含所有排序字段。
本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2717.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 0

还没有回复,来抢沙发~