不会。SQL 标准中 NULL 不等于 NULL,但多数数据库将所有 NULL 归为一组;空字符串 ” 与 NULL 默认不同组,需用 COALESCE 等显式合并;COUNT(*)统计所有行,COUNT(col)忽略 NULL;大小写敏感性取决于 collation;长字符串分组应优化为前缀或哈希。

GROUP BY 对字符串字段分组时,空值和 NULL 会被归为同一组吗?
不会。SQL 标准里 NULL 不等于 NULL,所以多个 NULL 值在 GROUP BY 中会被视为“无法比较”,但绝大多数数据库(如 PostgreSQL、SQL Server、Oracle)会 把所有 NULL 归为一个组;MySQL 默认行为也如此,但受 sql_mode 影响,比如开启 STRICT_TRANS_TABLES 不影响分组逻辑,而 ANSI 模式下更贴近标准。
- 实际写法中,别依赖“
NULL自动合并”做业务逻辑,显式处理更稳 - 如果想把空字符串
''和NULL当作不同类别,不用干预;但若想合并,得提前用COALESCE(col,'')或CASE WHEN col IS NULL THEN '' ELSE col END统一 - 测试时随手加一句
SELECT col, COUNT(*) FROM t GROUP BY col;,一眼看出NULL是单独一行还是被吞了
字符串分组后 COUNT(*) 和 COUNT(col) 结果为什么不一样?
因为 COUNT(*) 统计行数,包含 NULL 行;COUNT(col) 只统计 col 非 NULL 的行数——哪怕 col 是字符串类型,这条规则也不变。
- 常见错误:用
COUNT(name)想统计“有名字的用户数”,结果发现比预期少,其实是name字段存了大量NULL或空字符串 - 若字段允许
NULL,且业务上“空字符串”也算无效值,建议写成COUNT(NULLIF(name, ''))(PostgreSQL/MySQL 8.0+)或SUM(CASE WHEN name !='' AND name IS NOT NULL THEN 1 ELSE 0 END) -
COUNT(DISTINCT col)同样忽略NULL,这点和COUNT(col)一致
按字符串分组时,大小写敏感性会影响分组结果吗?
会,完全取决于字段的排序规则(collation)。例如 MySQL 中 utf8mb4_0900_as_cs 是大小写敏感,utf8mb4_0900_ai_ci 是不区分大小写、不区分重音。
- 查看当前字段排序规则:
SHOW FULL COLUMNS FROM table_name LIKE 'col_name';,看Collation列 - 临时强制大小写敏感分组:用
BINARY col(MySQL)或COLLATE "C"(PostgreSQL),如GROUP BY BINARY tag - 不建议在
GROUP BY里硬加LOWER()来“统一大小写”,除非你确认该字段没索引或不在乎性能;否则应建函数索引或调整列 collation - 字符集混用(比如 UTF8 和 GBK)可能导致隐式转换失败,直接报错
Illegal mix of collations
大数据量下对长字符串字段 GROUP BY 很慢,怎么优化?
长字符串(比如 TEXT 或超长 VARCHAR)直接 GROUP BY 会导致排序 / 哈希阶段内存占用高、磁盘临时文件多,甚至 OOM。
- 优先考虑是否真要按完整字符串分组:能不能用前缀?比如
GROUP BY LEFT(url, 50)(注意前缀需有业务意义) - 更稳妥的是加计算列 + 索引:MySQL 5.7+ 支持持久化计算列,PostgreSQL 支持表达式索引,例如
CREATE INDEX idx_tag_hash ON logs ((md5(tag))),然后GROUP BY md5(tag)(仅限去重场景,不可回查原值) - 确认
sort_buffer_size和tmp_table_size是否过小(MySQL),或work_mem(PostgreSQL),但调参治标不治本 - 如果只是想看高频关键词,先用
WHERE过滤再分组,比全表扫快得多
字符串分组看着简单,真正上线后卡顿、结果对不上、导出数据少几万条——八成出在 NULL 处理、collation 隐式转换、或者没意识到 GROUP BY 其实偷偷做了全文本哈希。动手前先 EXPLAIN 一下,比猜强。