MySQL 8.0.19+ 禁止TEXT字段直接参与GROUP BY,因其无固定长度、不支持哈希比较且易超内存限制;唯一合规绕过方式是先SUBSTRING截断再CAST为定长CHAR类型,但会引发索引失效、分组失真及结果不稳定等严重问题。

MySQL 8.0+ 直接拒绝 TEXT 字段参与 GROUP BY
不是报错“字段不在 GROUP BY 中”,而是根本无法把 TEXT 当作分组键——MySQL 8.0.19 起已明确禁止该操作,执行时会直接抛出类似 Unsupported type for key 或 Cannot group on BLOB/TEXT column 的错误。这和 ONLY_FULL_GROUP_BY 模式无关,是类型系统级限制。
为什么 SUBSTRING(content, 1, N) + CAST 是唯一可行的绕过路径
TEXT 不能直接分组,是因为它没有固定长度、不支持哈希比较,且可能超内存页限制。但 MySQL 允许对截取后的子串做显式类型转换:
-
SUBSTRING(content, 1, 255)必须先截断,用LEFT()不行——某些版本返回 BLOB 类型,依然被拒 -
CAST(SUBSTRING(content, 1, 255) AS CHAR(255))才算真正转成可分组的定长字符串类型 - 长度选 255 是安全边界:既避开 InnoDB 单索引键长上限(767 字节),又兼容多数前缀索引策略
GROUP BY text_prefix 后性能暴跌的三个隐性原因
即使语法跑通,GROUP BY CAST(SUBSTRING(note, 1, 255) AS CHAR(255)) 也会带来严重副作用:
- 无法利用原
note字段的索引——函数表达式导致索引失效 - 必须手动加前缀索引才能缓解:执行
ALTER TABLE logs ADD KEY idx_note_prefix (note(255)) - 如果实际内容前 255 字节高度重复(比如日志都以 "[ERROR]" 开头),分组桶数会远少于预期,聚合结果失真
真正该做的:别让 TEXT 成为分组依据
所有试图对 TEXT 分组的场景,几乎都暴露了设计缺陷:
- 想按“相似描述”聚类?该用 NLP 提取关键词后存入新列,再按关键词分组
- 想归档用户反馈?应提取业务维度(如
category、priority)作为分组主键,TEXT仅用于GROUP_CONCAT()展示 - 误用
SELECT *, COUNT(*) FROM t GROUP BY content?这语义本身就是错的——TEXT几乎不可能完全相等,分组结果不可控且无业务意义
最常被忽略的一点:哪怕你硬凑出能跑的 SQL,只要分组键依赖文本前缀,就永远无法保证结果稳定——换 MySQL 小版本、换字符集、甚至换客户端连接参数,都可能导致 SUBSTRING 截断行为变化。










