首页 / SQLite 入门教程 / LIMIT 与 OFFSET:分页

SQLite 入门教程

LIMIT 与 OFFSET:分页

本教程共 50 篇 · 第 20 篇 · 更新于 2026-07-31

sqliteLIMITOFFSET分页

20. LIMIT 与 OFFSET:分页

本节目标:学完本章你能用 LIMIT 控制返回多少行,用 OFFSET 跳过前面若干行,并写出正确的分页查询,同时明白深翻页的性能代价。

查询结果可能成千上万行,但屏幕一次装不下,接口也不能一次吐十万条。LIMIT 就是用来”掐头去尾只取一部分”的:它限制 SELECT 最多返回多少行。

最基本的 LIMIT 只跟一个数字——返回的行数上限:

SELECT name, age
FROM users
ORDER BY age DESC
LIMIT 5;

这条语句先按年龄降序排,再只取前 5 行。注意我特意写了 ORDER BY:LIMIT 截的是”当前结果集的前 N 行”,如果结果顺序没定,截出来的就是”任意 N 行”。所以 LIMIT 几乎总要和 ORDER BY 一起用,顺序上 ORDER BY 在前、LIMIT 在后。

OFFSET 负责”跳过前面几行”。比如你想跳过最年长的 5 个,看接下来的 5 个:

SELECT name, age
FROM users
ORDER BY age DESC
LIMIT 5 OFFSET 5;

意思是:先排序,跳过前 5 行,再取 5 行。OFFSET 5 就是”从下标 5(第 6 行)开始”。

分页(Pagination)是 LIMIT + OFFSET 最经典的用途。假设每页显示 10 条,要取第 p 页(p 从 1 开始),公式就是:

SELECT * FROM users
ORDER BY id
LIMIT 10 OFFSET (p - 1) * 10;

第 1 页 OFFSET 0,第 2 页 OFFSET 10,第 3 页 OFFSET 20……排序键这里用了 id(主键),因为它唯一且稳定,保证每一页不重不漏。请务必用稳定、唯一的排序列做分页,否则同一行可能在不同页重复出现或漏掉。

LIMIT 还有个简写:LIMIT 后面用逗号隔开两个数字,等价于”OFFSET, 行数”。下面两句意思相同:

SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 20;
SELECT * FROM users ORDER BY id LIMIT 20, 10;

这种写法更短,但可读性略差,团队里最好统一一种风格。

除了翻页,LIMIT 还能取”第 N 大/第 N 小”的值。思路是:先按目标列排好序,再用 LIMIT 1 OFFSET (N-1) 取那一行。例如”年龄第二大的用户”:

SELECT name, age
FROM users
ORDER BY age DESC
LIMIT 1 OFFSET 1;

排好降序后,第 0 行是最大,跳过 1 行取到的就是第二大。同理,“第三便宜的订单”就是 ORDER BY amount ASC 然后 LIMIT 1 OFFSET 2。这个套路在排行榜、取中位数附近的值时非常好用。

重点提示

LIMIT 只影响”返回给你多少行”,绝不改动表里的数据,也不会删除任何东西。它是查询输出端的裁剪,放心用。

实用技巧

翻页公式记牢:LIMIT 页大小 OFFSET (页码-1)*页大小,且排序键用唯一稳定的列(通常是主键 id)。这样分页既不重也不漏,是接口开发的基本功。

常见坑

第一,LIMIT 不写 ORDER BY 时截的是”任意前 N 行”,结果随版本/数据变化,千万别拿它当”抽样”。第二,OFFSET 越大越慢:数据库要先扫描并丢弃前面跳过的所有行,深翻页(比如 OFFSET 100000)性能会明显下滑。数据量大又要深翻页时,应改用”基于上次最大 id 的游标分页”而非一味加大 OFFSET。

LIMIT 还能取 0 或一个特殊值 -1:LIMIT 0 返回空集,常用来”只想知道这条 SELECT 会不会报错、结构对不对”而不真取数据;LIMIT -1 在 SELECT 里被当作”无限制”,等价于不写 LIMIT(这个写法可读性差,知道即可,别依赖)。

为什么不直接 SELECT * 全取回来再在程序里截取?两个原因:一是网络与内存——十万行全传回应用只为显示前 10 行,纯属浪费;二是语义清晰——分页、Top N 本就是查询的意图,写在 SQL 里谁都看得懂,也比在代码里切片更不容易出错。

再谈一个现实对比:OFFSET 分页(LIMIT size OFFSET n)实现简单,但越往后置越慢,因为数据库要真的扫过并丢弃前面 n 行。另一种叫”游标分页 / 键集分页”的做法是:记住上一页最后一条的 id,下一页用 WHERE id > 上一页最大id ORDER BY id LIMIT size。它不用 OFFSET,无论翻多深都只扫一页的量,性能稳定——代价是没法”跳到第 100 页”,只能一页页往后翻。列表很长又允许顺序浏览时,游标分页是更优解。

适用场景小结:后台管理列表、App 下拉刷新、Top N 榜单、取第 N 名、数据抽样预览,都是 LIMIT/OFFSET 的地盘。记住”ORDER BY + LIMIT”是固定搭档,分页公式用唯一键排序,深翻页换游标——这三条够你应付绝大多数列表需求。

还有一点常被忽略:LIMIT 减少的是”返回行数”,但 SELECT 写的列也会影响开销。SELECT * 配合 LIMIT 10 虽然只回 10 行,却把每行所有列都读出来了;如果只要两三个字段,写成 SELECT id, name 既能少传数据,也更聚焦。分页查询把”限制行数”和”只取必要列”结合,是接口性能的基本功。

另外提醒:LIMIT 截出来的是结果集的前 N 行,它和”随机取样”不是一回事。想随机抽几条,应当配合随机排序或随机函数,而不是裸 LIMIT——否则每次都拿到固定的前几行,样本毫无随机性,做统计或抽奖时会出大错。

实际写分页接口还要处理边界:最后一页不足一页大小时,LIMIT 自然返回剩余行,不需要特殊处理;但若用户传了一个超过总页数的页码,OFFSET 会越界得到空结果,前端要友好提示”没有更多了”。把 LIMIT/OFFSET 和总行数 COUNT 一起返回,前端才能正确画出页码器。这些虽是应用层细节,但都建立在你已掌握 LIMIT/OFFSET 之上。

小结一句:LIMIT 是查询的”出口阀”,OFFSET 是”快进键”,二者配合 ORDER BY 才能稳定输出你想要的片段。理解这三者的关系,分页、榜单、取样就都不再是难题,你也能在写第一条列表接口时心里有底。

类比小结:把结果集想成一卷长长的电影胶片。LIMIT 5 是”只洗印前 5 格”;OFFSET 5 是”跳过前 5 格再从第 6 格开始洗印”。翻页就是不断往后挪这个”取景框”。但胶片越长,你越往后挪,机器要倒带的距离就越长——这就是深翻页变慢的直观原因。

什么时候用 LIMIT/OFFSET?做列表页、下拉加载更多、取 Top N、取第 N 名,以及任何”只想要一部分结果”的场景。记住它和 ORDER BY 是天生一对,落单的 LIMIT 往往意味着隐藏 bug。