count(distinct column)是sql server 2022中统计去重总数最直接可靠的方式,支持多列组合去重、自动忽略null、语法标准;旧版如2016不支持多列会报错,且不可写成distinct count()或count(distinct *)。

COUNT(DISTINCT column) 是 SQL Server 2022 中统计去重总数最直接、最可靠的方式,语法标准、性能可控,且无需额外兼容性处理。
SQL Server 2022 支持 COUNT(DISTINCT) 多列组合
SQL Server 2017 起已完整支持多列 DISTINCT,2022 版本完全无限制:
-
COUNT(DISTINCT user_id, action_type)统计的是不同 (user_id, action_type) 二元组的数量,不是分别去重再相乘 - 旧版(如 SQL Server 2016 及更早)不支持该写法,会报错
Incorrect syntax near ',';2022 不再有此问题 - 若字段含
NULL,所有NULL在组合中被视为同一值,只计 1 次(例如(1, NULL)和(2, NULL)中的NULL不冲突,但两个(1, NULL)算重复)
常见错误:把 DISTINCT 写在 COUNT 外面
以下写法在 SQL Server 2022 中**语法非法**,会直接报错:
SELECT DISTINCT COUNT(user_id) FROM logs;
正确结构必须是 COUNT(DISTINCT ...),括号不能省,顺序不能颠倒。容易混淆的点:
-
COUNT(DISTINCT *)❌ 不合法 ——DISTINCT后必须明确列名或表达式 -
COUNT(DISTINCT user_id, created_date)✅ 合法,且推荐用于联合去重场景 - 如果想排除
NULL,不能依赖自动忽略逻辑来“掩盖业务意图”,应显式过滤:COUNT(DISTINCT CASE WHEN user_id IS NOT NULL THEN user_id END)
大数据量下 COUNT(DISTINCT) 明显变慢怎么办
SQL Server 2022 默认使用哈希聚合(Hash Aggregate)执行 COUNT(DISTINCT),当内存不足时会 spill 到 tempdb,I/O 激增。实操建议:
- 确认
user_id等字段是否有索引:复合索引如INDEX (tenant_id, user_id)在带 WHERE 条件时可能跳过排序,显著提速 - 避免在
DISTINCT字段上做函数操作,例如COUNT(DISTINCT UPPER(email))会强制计算每行,无法利用索引 - 若数据超千万行且对精度要求不高,可用近似算法替代:SQL Server 2022 **不原生支持**
APPROX_COUNT_DISTINCT(那是 Azure SQL / Synapse 的函数),此时应考虑预聚合或物化视图 - 临时调优可改用子查询写法:
SELECT COUNT(*) FROM (SELECT DISTINCT user_id FROM logs WHERE tenant_id = 123) AS t,有时优化器会选择索引嵌套循环而非哈希,实测更快
真正容易被忽略的是:即使用了 COUNT(DISTINCT),如果 WHERE 条件里隐式转换了字段类型(比如用字符串匹配 INT 主键),SQL Server 仍可能放弃索引,导致全表扫描——务必用 EXEC sp_executesql 参数化 + 查看执行计划确认是否走了索引 Seek。











