装机时配好数据库环境,开发或维护系统常会遇到数据量一大就卡顿的问题。比如后台要查用户列表,上万条记录全查出来,页面加载慢、内存爆掉、浏览器直接罢工。这时候,分页不是可选项,是必选项。
为什么不能一次查完再前端分页?
有人图省事,在程序里用 SELECT * FROM user 把全部数据捞出来,再用代码切片(比如 Python 的 list[10:20])。这在几百条数据时还凑合,一旦表里有几十万用户,光是网络传输+内存加载就得几秒,数据库连接池还可能被占满。真正的分页,得让数据库自己只吐出当前页要的那十几条。
主流数据库的分页写法
MySQL 8.0+:用 OFFSET + LIMIT 最直接
查第3页,每页10条(即跳过前20条,取10条):
SELECT id, username, email FROM user ORDER BY id DESC LIMIT 10 OFFSET 20;注意:ORDER BY 必须有,否则分页结果可能错乱;OFFSET 值 = (页码 - 1) × 每页条数。
MySQL 5.7 及更早:只能用 LIMIT m,n
上面的例子等价写法:
SELECT id, username, email FROM user ORDER BY id DESC LIMIT 20, 10;意思是“从第20条开始,取10条”。但这个语法容易看反,建议统一用 OFFSET + LIMIT 更清晰。
SQL Server:用 OFFSET FETCH(2012+ 推荐)
同样查第3页,每页10条:
SELECT id, username, email FROM user ORDER BY id DESC OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;必须带 ORDER BY,FETCH NEXT 不支持变量,但配合参数化查询很稳。
Oracle:ROWNUM 旧法易翻车,推荐用 FETCH FIRST(12c+)
老写法(不推荐):
SELECT * FROM (SELECT ROWNUM rn, t.* FROM (SELECT id, username, email FROM user ORDER BY id DESC) t WHERE ROWNUM <= 30) WHERE rn > 20;嵌套两层,性能差还难读。新写法清爽多了:
SELECT id, username, email FROM user ORDER BY id DESC OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;PostgreSQL:跟 MySQL 类似,也支持 OFFSET + LIMIT
SELECT id, username, email FROM user ORDER BY id DESC LIMIT 10 OFFSET 20;而且 PostgreSQL 对大偏移量(比如 OFFSET 100000)做了优化,比 MySQL 的 LIMIT 100000,10 更靠谱些。
实战小提醒
分页时别只盯着语法——id 是主键且连续还好说,如果按 create_time 排序,又存在时间相同的情况,不同页可能漏数据或重复。稳妥做法是:ORDER BY create_time DESC, id DESC,把 id 当第二排序字段兜底。
另外,真遇到百万级数据分页,OFFSET 越大越慢(数据库要先扫前面所有行)。这时候可以考虑游标分页(用上一页最后一条的 id 当起点),不过那是进阶玩法了,基础装机阶段先掌握上面这些够用了。