GROUP BY本质是结构化聚合,不支持非结构化数据直接分组;JSON/TEXT/BLOB字段需先提取结构化字段或建生成列再分组,否则因字符串差异、无索引、语义失真导致统计错误或性能崩溃。

SQL 的 GROUP BY 本质是结构化聚合操作,它不支持“非结构化数据”本身——真正的问题不是“怎么用 GROUP BY 处理 JSON/文本/图片”,而是:当字段内容是 JSON 字符串、长文本、XML 或二进制 blob 时,你强行把它塞进 GROUP BY 子句或 SELECT 列表,会立刻暴露语义断裂和执行风险。
GROUP BY 对 JSON 字段直接分组几乎必然失效
MySQL 或 PostgreSQL 中若有一列 meta_data 存的是 JSON 字符串(如 {"region":"sh","level":2}),直接写 GROUP BY meta_data 看似可行,但实际踩坑点极多:
- JSON 字符串的空格、换行、键顺序差异(
{"a":1,"b":2}vs{"b":2,"a":1})会导致哈希值不同,同一逻辑对象被拆成多组 - PostgreSQL 的
jsonb类型虽能标准化键序,但 MySQL 的JSON类型默认不归一化,GROUP BY比较的是原始字符串字节流 - 哪怕内容完全相同,如果某行是
NULL、某行是'null'字符串、某行是空对象{},三者在GROUP BY中互不相等,也不归为同一 NULL 组 - 性能灾难:JSON 字段通常无索引,
GROUP BY只能全表扫描 + 内存排序,百万级表可能卡死
用 SUBSTRING 或正则提取后再分组,极易丢失精度
常见“取巧”做法是先用 SUBSTRING_INDEX()、REGEXP_SUBSTR() 或 JSON_EXTRACT() 提取结构化片段,再分组。但这类操作天然脆弱:
-
JSON_EXTRACT(meta_data, '$.region')返回带双引号的字符串(如"sh"),而业务值可能是sh(无引号),导致分组错位 - 正则匹配失败时返回
NULL,所有失败行被归为一组,掩盖脏数据问题 - 提取表达式一旦写错(比如路径拼错、未处理嵌套数组),结果无声失效——查不出错,但统计数对不上
- MySQL 8.0+ 要求
JSON_EXTRACT结果参与GROUP BY时,必须显式加CAST(... AS CHAR),否则报类型不匹配
TEXT/BLOB 字段不能直接出现在 GROUP BY 中(MySQL 严格模式下)
MySQL 5.7+ 启用 only_full_group_by 后,TEXT、MEDIUMTEXT、BLOB 类型字段禁止出现在 GROUP BY 子句里,报错信息明确:
Miller (mlr) 是一个命令行工具,用于查询、整形和重新格式化名称索引数据,如 CSV、TSV、JSON 和 JSON Lines。它将 awk、sed、cut、join 和 sort 的功能整合到一个专为结构化数据处理而构建的单一工具中。
ERROR 1055: Expression #X of SELECT list is not in GROUP BY clause and contains nonaggregated column 't.content' which is not functionally dependent on columns in GROUP BY clause
这不是限制,是保护——因为 TEXT 字段无法建哈希索引,数据库无法高效分组;即使绕过(如用 SUBSTR(content, 1, 255)),也只截前缀,语义已失真。
真正该做的,不是硬分组,而是提前结构化
面对含 JSON/TEXT 的表,GROUP BY 不是第一选择。优先做这三件事:
- 把高频查询字段(如 region、status、category)从 JSON 中抽出来,建独立列 + 索引,再
GROUP BY这些列——这是唯一能兼顾性能与语义准确的做法 - 用生成列(MySQL 5.7+ 的
STOREDgenerated column)自动解析 JSON 并持久化关键字段,让优化器能走索引 - 确认业务是否真需要“按全文模糊聚类”——如果是,
GROUP BY不适用,该上向量相似度或 Elasticsearch
别试图用 GROUP_CONCAT() 或 ANY_VALUE() 强行包裹非结构化字段:它们解决不了语义歧义,只会把问题延迟到报表上线那天才爆发。

















