在关系数据库中,“深分页”(例如 LIMIT 1000000, 20,即取第 100 万条之后的 20 条)往往性能很差,数据库设计和使用中通常建议避免。原因主要来自执行机制、索引使用和代价模型几个方面:
以常见 SQL 为例:
SELECT * FROM orders
ORDER BY create_time
LIMIT 1000000, 20;
数据库实际执行过程通常是:
create_time 排序(或沿索引顺序扫描)也就是说:偏移量越大,扫描和临时丢弃的数据越多。
假设 create_time 有索引:
OFFSET 1000000 仍意味着要沿索引走 100 万步索引减少了“排序”成本,但没有减少跳过的行数。
如果查询不是“覆盖索引”:
SELECT * FROM orders ORDER BY create_time LIMIT 1000000, 20;
数据库需要:
前 100 万次回表虽然是“顺序索引”,但回表本身是随机 IO,深分页会放大 IO 成本。
如果没有合适索引:
filesort深分页 = 大数据集排序 + 大量丢弃。
深分页还容易遇到:
例如:
SELECT * FROM orders
WHERE create_time < :last_time
ORDER BY create_time DESC
LIMIT 20;
优点:
SELECT * FROM orders
JOIN (
SELECT id FROM orders
ORDER BY create_time
LIMIT 1000000, 20
) t ON orders.id = t.id;
减少回表行数。
关系数据库避免深分页,是因为
OFFSET越大,扫描、排序和丢弃的数据越多,索引也无法消除这种线性代价,最终导致性能急剧下降。
如果你愿意,我也可以结合 MySQL / PostgreSQL / Oracle 的具体执行计划来进一步说明。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。