LIMIT
导学
查询结果可能有成千上万条,但用户一次只能看一页。LIMIT 是 MySQL 提供的分页利器,也是控制返回结果数量的最简洁方式。
定义
LIMIT:MySQL 特有的子句(非 SQL 标准),用于限制 SELECT 语句返回的行数。通常与 ORDER BY 配合使用,实现分页查询。
注意:SQL 标准使用
FETCH FIRST,Oracle 使用ROWNUM,SQL Server 使用TOP。MySQL 和 PostgreSQL 使用LIMIT。
核心语法
-- MySQL 5.7 两种写法
SELECT 列 FROM 表 LIMIT 数量;
SELECT 列 FROM 表 LIMIT 偏移量, 数量;
SELECT 列 FROM 表 LIMIT 数量 OFFSET 偏移量;
演示数据准备
DROP TABLE IF EXISTS employees;
CREATE TABLE employees (
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(20),
dept VARCHAR(20),
score DECIMAL(5,2)
);
INSERT INTO employees (emp_name, dept, score) VALUES
('大翔', '技术部', 100),
('白歌', '技术部', NULL);
当前 employees 表中的完整数据如下:
| emp_id | emp_name | dept | score |
|---|---|---|---|
| 1 | 大翔 | 技术部 | 100 |
| 2 | 白歌 | 技术部 | NULL |
SQL 示例
场景一:只取前 N 条
当前数据状态:见上文 employees 表完整数据。
执行语句:
SELECT emp_name, dept, score FROM employees
ORDER BY score DESC, emp_id ASC
LIMIT 2;
操作后结果:
| emp_name | dept | score |
|---|---|---|
| 大翔 | 技术部 | 100 |
| 白歌 | 技术部 | NULL |
结果解读:先按 score 降序排列(相同分数再按 emp_id 升序),然后只取前 2 条。由于表中只有 2 条数据,因此返回全部记录。注意:没有 ORDER BY 的 LIMIT 返回的"前 N 条"是不确定的,因为物理存储顺序不可预测。
场景二:分页查询(第 1 页,每页 2 条)
当前数据状态:见上文 employees 表完整数据,已按 score 降序、emp_id 升序排列。
执行语句:
SELECT emp_name, dept, score FROM employees
ORDER BY score DESC, emp_id ASC
LIMIT 0, 2;
-- 等价于
-- LIMIT 2 OFFSET 0;
操作后结果:
| emp_name | dept | score |
|---|---|---|
| 大翔 | 技术部 | 100 |
| 白歌 | 技术部 | NULL |
结果解读:LIMIT 0, 2 表示跳过 0 行,取 2 行,即第 1 页的数据。由于表中只有 2 条数据,因此返回全部记录。
场景三:分页查询(第 2 页,每页 2 条)
当前数据状态:见上文 employees 表完整数据,已按 score 降序、emp_id 升序排列。
执行语句:
SELECT emp_name, dept, score FROM employees
ORDER BY score DESC, emp_id ASC
LIMIT 2, 2;
-- 等价于
-- LIMIT 2 OFFSET 2;
操作后结果:
| emp_name | dept | score |
|---|
结果解读:LIMIT 2, 2 表示跳过前 2 行,取接下来的 2 行,即第 2 页的数据。由于表中只有 2 条数据,因此没有数据返回。
场景四:分页查询(第 3 页,每页 2 条)
当前数据状态:见上文 employees 表完整数据,已按 score 降序、emp_id 升序排列。
执行语句:
SELECT emp_name, dept, score FROM employees
ORDER BY score DESC, emp_id ASC
LIMIT 4, 2;
-- 等价于
-- LIMIT 2 OFFSET 4;
操作后结果:空结果集(0 行)。
结果解读:跳过前 4 行,取接下来的 2 行。由于表中只有 2 条数据,因此没有数据返回。
分页公式:LIMIT (页码 - 1) * 每页条数, 每页条数
场景五:获取第 N 高的绩效分(经典面试题)
当前数据状态:见上文 employees 表完整数据。
执行语句:
-- 获取绩效分第 2 高的员工
SELECT emp_name, score FROM employees
ORDER BY score DESC, emp_id ASC
LIMIT 1, 1;
操作后结果:
| emp_name | score |
|---|---|
| 白歌 | NULL |
结果解读:先按 score 降序排列(相同分数按 emp_id 升序),跳过前 1 条(大翔 100),取第 2 条,即白歌 NULL。
场景六:LIMIT 0 的妙用
当前数据状态:见上文 employees 表完整数据。
执行语句:
SELECT emp_name, score FROM employees
WHERE dept = '技术部'
ORDER BY score DESC
LIMIT 0;
操作后结果:空结果集(0 行)。
结果解读:LIMIT 0 不返回任何数据行,但会返回结果集的列结构(列名、类型)。这在程序化地探测 SQL 语法正确性和结果集元数据时非常有用,比返回大量数据再丢弃要高效得多。
LIMIT 的性能陷阱
深度分页问题
执行语句(糟糕示例):
-- 糟糕:偏移量100万时极慢
SELECT * FROM employees
ORDER BY emp_id ASC
LIMIT 1000000, 10;
结果解读:MySQL 仍然需要扫描/排序前 1,000,010 行,然后丢弃前 1,000,000 行。偏移量越大,性能越差。
优化方案:使用覆盖索引 + 延迟关联
为了演示这个优化,我们假设有一张更大的表,其核心思路是:
-- 优化:利用主键索引减少回表
SELECT s.* FROM employees s
INNER JOIN (
SELECT emp_id FROM employees
ORDER BY emp_id ASC
LIMIT 1000000, 10
) tmp ON s.emp_id = tmp.emp_id;
结果解读:子查询只取 emp_id(索引列),避免了深度分页时的回表开销,外层再通过主键关联取完整数据。这是处理大数据量深度分页的经典优化手段。
常见误区
| 误区 | 正解 |
|---|---|
LIMIT 可以不配合 ORDER BY | 合法但不推荐,结果顺序不确定,分页会混乱。 |
LIMIT 能减少服务器计算量 | LIMIT 只在最后阶段截断结果,前面的扫描、排序、连接操作一样不少。 |
| 深度分页(大 OFFSET)和浅分页一样快 | 偏移量越大性能越差,需用延迟关联等技巧优化。 |
LIMIT 是 SQL 标准 | LIMIT 是 MySQL 扩展,标准 SQL 使用 FETCH FIRST。 |
面试考点
Q:LIMIT 在 SQL 执行顺序中的位置?
LIMIT是最后执行的步骤,在ORDER BY之后。它只影响返回给客户端的行数,不影响查询过程中的计算量。
Q:MySQL 深度分页怎么优化?
- 业务上限制最大页码(如只能翻到 100 页);2. 使用"记录上一页最后 ID"的方式代替 OFFSET;3. 延迟关联(Deferred Join),先
LIMIT取主键,再关联取完整行。
Q:LIMIT 0 有什么用?
快速验证 SQL 语法和获取结果集结构(列名、类型),而不返回任何数据行。常用于程序化的元数据探测。
Q:MySQL 中 LIMIT 10 和 LIMIT 0, 10 有什么区别?
没有区别。
LIMIT 10是LIMIT 0, 10的简写,都表示从第 1 行开始取 10 行。
小结
LIMIT用于限制返回行数,是 MySQL 分页的核心工具- 分页公式:
LIMIT (page-1)*size, size - 深度分页(大 OFFSET)性能差,需要优化
- 始终配合
ORDER BY使用,确保分页顺序稳定 LIMIT 0可用于获取结果集结构而不返回数据
下一章引子:学会了筛选、排序、分页,接下来深入了解 WHERE 子句中的各种运算符。