电脑工场
白蓝主题五 · 清爽阅读
首页  > 软件入门

SQL查询分页写法:MySQL、SQL Server、PostgreSQL怎么写才不翻车

做后台开发或者写管理后台时,经常要查数据列表——用户列表、订单列表、日志列表……一查就是几千上万条。直接 SELECT * FROM user 全拉出来?页面卡死,浏览器崩溃,老板路过都得皱眉。这时候就得用分页。

为什么不能用 LIMIT 0,10 这种写法?

其实可以,但得看数据库类型。MySQL 支持 LIMIT offset, size,比如:

SELECT id, name, email FROM user ORDER BY id DESC LIMIT 0, 20;

这是查第1页,每页20条。下一页就写 LIMIT 20, 20,再下一页 LIMIT 40, 20……看起来挺直白,但注意:当 offset 很大(比如 100000),MySQL 会先扫前10万行再扔掉,性能直线下降。线上查第5000页?小心DBA半夜敲你门。

不同数据库的分页写法差异

MySQL 8.0+ 推荐用 ROW_NUMBER()

如果你用的是 MySQL 8.0 或更新版本,可以用窗口函数优化深分页:

SELECT id, name, email FROM (
  SELECT id, name, email, ROW_NUMBER() OVER (ORDER BY id DESC) AS rn
  FROM user
) t WHERE rn BETWEEN 10001 AND 10020;

这样避免了大 offset 扫描,实际执行更稳。

SQL Server 用 OFFSET-FETCH

SQL Server 2012 起支持标准分页语法:

SELECT id, name, email 
FROM user 
ORDER BY id DESC 
OFFSET 10000 ROWS FETCH NEXT 20 ROWS ONLY;

语义清晰,性能也比老式 TOP + NOT IN 方案靠谱得多。

PostgreSQL 就最省心

原生支持 OFFSET-FETCH,和 SQL Server 一样写法:

SELECT id, name, email 
FROM "user" 
ORDER BY id DESC 
OFFSET 10000 LIMIT 20;

注意:PostgreSQL 里 LIMITOFFSET 是标准组合,顺序不能反,且 OFFSET 必须配合 ORDER BY 使用,否则结果不稳定。

一个小提醒:别忘了加索引

不管哪种写法,如果 ORDER BY 的字段没索引,分页照样慢。比如按 created_at 分页,就在这个字段建个索引:

CREATE INDEX idx_user_created ON user(created_at DESC);

实测过,没索引时查第1000页要3秒,加完索引压到80ms以内。

实战小技巧

真上线时,别硬算 offset。比如用户点“下一页”,后端最好记下当前页最后一条记录的 ID(比如 id=5678),下次查就写:

SELECT id, name, email FROM user 
WHERE id < 5678 
ORDER BY id DESC LIMIT 20;

这叫“游标分页”,跳过所有 offset 计算,响应快还稳定,适合无限滚动场景。