sql server 2012+中offset-fetch是唯一原生分页语法,必须配合order by使用,偏移量为(@pagenumber-1)@pagesize,且不支持返回总条数,需额外执行count()查询,where条件须严格一致。

SQL Server 中用 OFFSET-FETCH 实现分页并统计总数
在 SQL Server 2012+,OFFSET-FETCH 是最直接的分页写法,但它本身不返回总条数,必须额外查一次 COUNT(*)。常见错误是把 COUNT(*) 和分页查询塞进同一个 SELECT —— 这会导致语法报错或逻辑混乱。
正确做法是用两个独立查询,或用临时表/变量缓存总数。注意:两次扫描同一张表可能影响性能,尤其数据量大时。
- 分页部分用
SELECT ... ORDER BY xxx OFFSET @skip ROWS FETCH NEXT @take ROWS ONLY - 总数单独执行
SELECT COUNT(*) FROM table WHERE ...(WHERE 条件必须和分页查询完全一致) - 把两个结果封装进存储过程输出参数或结果集,例如:
@total_count INT OUTPUT - 避免在分页查询里加
SELECT COUNT(*) OVER()——虽然能返回每行带总数,但会拖慢速度,且对大数据集不可控
MySQL 8.0+ 使用 LIMIT + SQL_CALC_FOUND_ROWS 已被弃用
SQL_CALC_FOUND_ROWS 在 MySQL 8.0.17 起被移除,现在必须显式调用 SELECT FOUND_ROWS(),但该函数依赖上一条语句是否用了 LIMIT,且并发下不可靠。实际项目中别再依赖它。
推荐方案是:先执行带 LIMIT 的分页查询,再立即执行同条件的 SELECT COUNT(*)。注意 WHERE 条件字符串必须严格一致,否则总数和分页数据对不上。
- 分页语句:
SELECT * FROM user WHERE status = 1 ORDER BY id DESC LIMIT 10 OFFSET 20 - 总数语句:
SELECT COUNT(*) FROM user WHERE status = 1 - 不要在分页语句后加
UNION ALL拼总数——类型不匹配、列数不一致,直接报错 - 若用预处理语句(如 PDO),确保两次查询共用同一连接,避免事务隔离导致数据不一致
PostgreSQL 中用 SELECT ... LIMIT/OFFSET 配合子查询取总数
PostgreSQL 不支持类似 SQL Server 的窗口函数嵌套总数返回,但可以用子查询或 CTE 把总数“算进来”。不过要注意:子查询里的 COUNT(*) 会被执行一次,而外层分页仍要扫描全表(除非加索引优化),性能比分开查还差。
更稳妥的做法仍是两步:先 SELECT COUNT(*),再 SELECT ... LIMIT ... OFFSET ...。如果必须单条语句返回,可用 WITH CTE:
WITH total AS (SELECT COUNT(*) AS cnt FROM orders WHERE created_at > '2024-01-01'), paged AS (SELECT * FROM orders WHERE created_at > '2024-01-01' ORDER BY id DESC LIMIT 10 OFFSET 0) SELECT paged.*, total.cnt FROM paged CROSS JOIN total;
但注意:CTE 中的 total 仍会触发一次全表扫描,且 CROSS JOIN 对空结果集行为不易控制。
存储过程里怎么组织这两部分才不容易出错
最容易踩的坑不是语法,而是 WHERE 条件写两遍却漏改一处,导致分页数据和总数不匹配。比如搜索关键词只在分页里加了 LIKE,总数里忘了加,结果前端显示“共 100 条”,实际只查出 5 条。
- 把 WHERE 条件抽象成变量或参数,例如:
DECLARE @where_clause NVARCHAR(MAX) = N'WHERE status = @status AND name LIKE @name',然后在两个查询里复用 - 使用动态 SQL 时,务必用
sp_executesql(SQL Server)或EXECUTE(PostgreSQL)传参,防止注入,也方便复用条件 - 输出总条数建议用
OUTPUT参数,而不是多结果集——某些客户端驱动(如旧版 ODBC)对多结果集支持不稳定 - 如果分页字段无索引,
OFFSET 10000会非常慢,这时总数查询也可能卡住;先确认ORDER BY字段有合适索引
分页本身不难,难的是让总数和分页真正对应。条件同步、索引覆盖、执行计划一致性,这三点漏掉任何一环,上线后都可能引发数据错位。











