在数据库查询操作中,当表内数据量达到成千上万甚至更多时,直接执行全表查询会返回大量冗余数据,既浪费数据库资源,也会让前端展示压力剧增,此时使用LIMIT实现分页查询是非常实用的解决方案。LIMIT可以指定查询结果返回的最大行数,也能结合偏移量控制从哪一行开始返回数据,适配不同场景的分页需求。

LIMIT分页的基本语法
在MySQL、PostgreSQL等数据库中,LIMIT分页的基础语法有两种常见形式,第一种是只指定返回的行数:
-- 只返回查询结果的前10条数据 SELECT * FROM user_table LIMIT 10;
第二种是指定偏移量和返回行数,语法为LIMIT 偏移量, 返回行数,其中偏移量是从0开始计数的,代表跳过前面多少条数据:
-- 跳过前10条数据,返回接下来的10条数据,也就是第11到20条 SELECT * FROM user_table LIMIT 10, 10;
还有另一种等价的写法,使用OFFSET关键字明确偏移量,可读性更强:
-- 和上面的语句效果完全一致 SELECT * FROM user_table LIMIT 10 OFFSET 10;
不同数据库中的LIMIT差异
不是所有关系型数据库都支持LIMIT语法,不同数据库的分页实现方式有所区别:
- MySQL、PostgreSQL、SQLite都原生支持LIMIT分页语法,用法和上述示例一致。
- Oracle数据库不支持LIMIT,需要使用
ROWNUM来实现分页,示例代码如下:
-- Oracle中实现第11到20条数据的查询
SELECT * FROM (
SELECT t.*, ROWNUM rn FROM (
SELECT * FROM user_table ORDER BY id
) t WHERE ROWNUM <= 20
) WHERE rn > 10;
- SQL Server在早期版本中使用
TOP配合子查询实现分页,2012及之后版本支持OFFSET FETCH语法,和LIMIT的OFFSET用法类似:
-- SQL Server 2012+ 分页查询第11到20条数据 SELECT * FROM user_table ORDER BY id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
常见分页场景的实现
前端常规分页
前端分页通常会传递两个参数:当前页码pageNum和每页条数pageSize,后端需要把这两个参数转换为LIMIT的偏移量和返回行数,转换公式为:偏移量 = (pageNum - 1) * pageSize。示例代码如下:
// Java中计算LIMIT参数 int pageNum = 2; // 当前第2页 int pageSize = 10; // 每页10条 int offset = (pageNum - 1) * pageSize; // 偏移量为10 int limit = pageSize; // 返回行数为10 // 拼接SQL:SELECT * FROM user_table LIMIT 10, 10
滚动加载分页
滚动加载场景不需要页码,而是记录上一页最后一条数据的唯一标识,比如最后一条数据的id是100,查询下一页就返回id大于100的10条数据,这种方式比偏移量分页性能更好,尤其是数据量大的时候:
-- 上一页最后一条数据id为100,查询下一页10条数据 SELECT * FROM user_table WHERE id > 100 ORDER BY id LIMIT 10;
LIMIT分页的性能优化
当偏移量很大时,比如LIMIT 100000, 10,数据库需要先扫描前100010条数据,再丢弃前100000条,性能会明显下降,可以通过以下方式优化:
- 尽量使用有序的唯一索引字段作为查询条件,比如上面的id字段查询,避免全表扫描。
- 如果业务允许,优先使用基于上次查询结果的滚动分页,而不是大偏移量的分页。
- 可以给查询字段添加合适的索引,减少扫描的数据量。
另外需要注意,使用LIMIT分页时一定要搭配ORDER BY子句,否则返回的数据顺序是不确定的,分页结果会出现重复或者遗漏的问题。