必须用 COUNT_BIG 而不是 COUNT 当查询结果可能 ≥ 2,147,483,648 行时,否则会因 int 溢出报错;适用于大宽表扫描、GROUP BY 分组计数、开窗函数及 UNION ALL 后聚合等场景。

COUNT_BIG 是 SQL Server 中唯一能安全返回 bigint 类型计数结果的聚合函数,当你面对行数可能超过 21.4 亿(即 int 最大值 2,147,483,647)的表或窗口计算时,必须用它替代 COUNT,否则会触发算术溢出错误。
什么时候必须用 COUNT_BIG 而不是 COUNT
当查询结果可能 ≥ 2,147,483,648 行时,COUNT 会直接报错:Msg 8115, Level 16, State 2: Arithmetic overflow error converting expression to data type int.
- 大宽表全量扫描(如日志表、审计表、历史归档表)
- 带
GROUP BY的分组计数,其中某一分组行数极多 - 开窗函数中使用
COUNT(*) OVER (PARTITION BY ...),且分区数据量超int上限 - 与
UNION ALL后再聚合的场景——合并后总行数可能突破int范围
COUNT_BIG(*) 和 COUNT_BIG(column) 的行为差异
COUNT_BIG(*) 统计所有行(含 NULL),不依赖任何列;COUNT_BIG(column) 只统计该列非 NULL 值的行数。两者都返回 bigint,但语义不同,不能互换。
-
COUNT_BIG(*)不接受DISTINCT,语法上不合法 -
COUNT_BIG(column)支持ALL(默认)和DISTINCT,例如:COUNT_BIG(DISTINCT user_id) - 如果
column是tinyint或int类型,COUNT_BIG仍返回bigint,类型提升由函数本身保证,不依赖输入类型
在开窗函数中用 COUNT_BIG 避免隐式截断
开窗聚合若用 COUNT,即使最终结果没超 int,SQL Server 也可能在中间计算阶段按 int 处理,导致意外溢出。显式用 COUNT_BIG 可彻底规避。
示例:对每用户统计其订单数,且用户订单量可能达数亿
SELECT user_id, COUNT_BIG(*) OVER (PARTITION BY user_id) AS order_cnt_big FROM orders;
- 不要写成
COUNT(*) OVER (...)然后 CAST,CAST 是事后补救,溢出已发生 -
OVER子句中不支持DISTINCT,所以COUNT_BIG(DISTINCT ...)不能用于开窗 - 若需去重计数 + 开窗,得用子查询或 CTE 先去重,再套
COUNT_BIG(*)
和 SUM、AVG 等其他聚合函数混用时的类型一致性
COUNT_BIG 返回 bigint,但和其他聚合函数(如 SUM(int_col) 返回 int)一起 SELECT 时,SQL Server 不会自动把整行转为 bigint。如果你后续要加总多个 COUNT_BIG 结果,或参与计算,要注意显式转换。
- 错误写法:
SELECT COUNT_BIG(*) + SUM(some_int_col)—— 若SUM溢出仍是int错误 - 稳妥写法:
SELECT COUNT_BIG(*) + ISNULL(CAST(SUM(some_int_col) AS bigint), 0) - 聚合字段别名若用于应用层解析,建议明确标注类型意图,比如命名成
row_count_big而非cnt
真正容易被忽略的是:很多 DBA 在建监控视图或导出统计脚本时,习惯性沿用 COUNT(*),直到某天某张表突破 21 亿行才突然失败。只要涉及超大表、历史归档、或未来可扩展性设计,COUNT_BIG(*) 应作为默认选择,而不是“等报错再改”。

















