用group by+count()统计字段频次最可靠,需显式order by count() desc排序;null自成一组,排除需加where;json数组须用json_table拆解;区分大小写取决于collation。

用 GROUP BY + COUNT() 统计字段值频次
直接对目标字段 GROUP BY,再用 COUNT(*) 计数是最常用、最可靠的方式。它不依赖字符串拆分或正则,适用于所有数据类型(包括 NULL)。
- 默认情况下,
GROUP BY会把NULL当作一个独立分组,如果想排除空值,加WHERE column_name IS NOT NULL - 若字段是文本但含多余空格,建议先用
TRIM()处理,否则'abc'和'abc '会被算作不同值 - 结果默认无序,需要按频次排序时,必须显式写
ORDER BY COUNT(*) DESC
示例:
SELECT status, COUNT(*) AS freq FROM orders GROUP BY status ORDER BY freq DESC;
处理 JSON 字段里多个值的频次统计
当字段存的是 JSON 数组(如 ["tag1","tag2"]),不能直接 GROUP BY 整个字段——那只会统计 JSON 字符串本身的重复次数,而非内部元素。
- MySQL 8.0+ 可用
JSON_TABLE()拆开数组,再做聚合;5.7 需借助递归 CTE 或应用层处理 - 常见错误是用
LIKE或INSTR()粗暴匹配,会导致重复计数(如"tag12"被误认为含"tag1") - 如果 JSON 结构不规范(比如混用单双引号、有换行),
JSON_VALID()先校验,避免JSON_TABLE()返回空结果
示例(MySQL 8.0):
SELECT jt.tag, COUNT(*) AS freq FROM logs, JSON_TABLE(tags, '$[*]' COLUMNS (tag TEXT PATH '$')) AS jt GROUP BY jt.tag;
区分大小写与字符集影响
统计结果是否区分大小写,取决于字段的排序规则(collation)。例如 utf8mb4_0900_as_cs 是区分大小写的,而 utf8mb4_unicode_ci 默认不区分。
- 执行
SHOW FULL COLUMNS FROM table_name LIKE 'column_name';查看当前 collation - 临时强制不区分:在
GROUP BY中用LOWER(column_name),但会无法使用索引,大数据量时慎用 - 建表时就定好 collation 最稳妥;已存在表可通过
ALTER TABLE ... MODIFY COLUMN ... COLLATE ...修改
性能敏感场景下的替代方案
当表超大(千万级)、且只是偶尔查某字段频次,全表 GROUP BY 可能慢到不可接受。
- 优先检查该字段是否有索引——即使只是普通 B-tree 索引,也能加速
GROUP BY扫描 - 高频查询可建物化视图(MySQL 8.0+ 支持通过汇总表模拟),或用
INSERT ... ON DUPLICATE KEY UPDATE实时维护频次表 - 避免在
WHERE条件里对字段做函数操作(如WHERE UPPER(status) = 'DONE'),这会让索引失效,连带拖慢后续GROUP BY
真正容易被忽略的是:频次统计本身不难,难的是明确“统计口径”——要不要去重?空值怎么算?大小写算不算不同值?这些必须和业务方对齐,而不是一上来就写 SQL。











