mysql报error 1118或1055是因group by字段定义长度总和超1024字节,触发b-tree索引键长硬限制;需按utf8mb4实际字节计算,优先拆分字段而非截断或哈希。

MySQL报ERROR 1118或1055,实际是GROUP BY字段总长超1024字节
这不是配置问题,也不是SQL写法错,而是MySQL对B-tree索引键长度的硬限制在作祟——哪怕你没建索引,GROUP BY a, b, c也会按字段定义长度算哈希键,总和超1024字节就直接拦住。常见于VARCHAR(2000) + TEXT字段混用、多地址字段拼接等场景。
- 先确认是否真超限:
SELECT LENGTH(CONVERT(col1 USING utf8mb4)) + LENGTH(CONVERT(col2 USING utf8mb4)) + ... FROM dual,别只看表定义,utf8mb4下中文占4字节 - 拆分比截断更安全:把
full_address VARCHAR(2000)拆成province VARCHAR(32)、city VARCHAR(64)、street VARCHAR(128),总长可控且语义完整 - 慎用
SUBSTRING(col, 1, 255):能绕过报错,但“北京市朝阳区建国路8号”和“北京市朝阳区建国路88号”可能被截成相同前缀,归为一组 -
MD5(col)不推荐:32字节未必省空间,且业务上无法反查原始值,审计或导出时会卡住
PostgreSQL里GROUP BY长文本触发Hash Key溢出怎么办
PostgreSQL不会因字段定义长度报错,但执行时若GROUP BY long_text_col导致内存不足,EXPLAIN (ANALYZE, BUFFERS)会显示Hash Key或Sort Method: external merge Disk——这是计算层撑爆,不是存储层问题。
- 优先用前缀分组:
GROUP BY SUBSTRING(description, 1, 300),再确保该长度 ≤ 目标列定义(如VARCHAR(300)) - 聚合后存再扩展:用
STRING_AGG(DISTINCT col, ';')或ARRAY_AGG(col)压缩,INSERT到TEXT字段结果表,避免中间计算膨胀 - 别在长字段上建索引:即使不参与GROUP BY,
VARCHAR(8000)列建普通索引会受B-tree页内键长限制(767/3072字节),导致DDL失败 - 检查
work_mem是否过小:单次Hash分组内存不足时,调大它(如设为64MB)可能比改逻辑更快见效
GROUP BY字段太多,执行计划出现Using temporary; Using filesort
这说明MySQL彻底放弃索引分组,改用磁盘临时表排序,10万行查询耗时可能从20ms跳到3秒以上。不是加tmp_table_size就能解决,是分组维度本身失控了。
- 索引顺序必须完全匹配:
INDEX idx(status, user_id)对GROUP BY user_id, status无效,字段顺序错一个就白搭 - 删掉业务非必需字段:比如报表只要“地区+状态”,就别硬加上
device_type、ip_address这种高基数列 - 用关联表降维:
JOIN users u ON o.user_id = u.id GROUP BY o.region, u.tier,把千万级user_id换成3档tier,分组桶数从亿级降到百级 - 子查询先聚合再JOIN:把
SELECT region, city, dept, COUNT(*)拆成子查询算region+user_id,再JOIN用户维度表,避免主查询笛卡尔爆炸
临时表能绕过GROUP BY字段限制,但容易踩哪些坑
当必须10+字段分组又无法精简时,CREATE TEMPORARY TABLE是权衡解法,但它把“一次查完”变成“先写再读”,引入新风险。
- 连接池复用时残留数据:加
DROP TEMPORARY TABLE IF EXISTS temp_agg开头,否则旧连接里的临时表可能干扰新查询 - 事务可见性问题:临时表内容不在事务快照内,
INSERT ... SELECT过程中其他连接看不到中间态,但COMMIT后才可见 - 写放大明显:100万行原始数据,按10字段分组后生成50万行临时表,IO和内存压力翻倍
- 别用子查询替代:
SELECT * FROM (SELECT a,b,c FROM t GROUP BY a,b,c) t1可能被优化器重执行多次,不如显式建临时表可控
实际中,最常被忽略的是字段语义和计算模型的错配——你以为要按完整地址分组,其实业务真正需要的是“城市层级聚合”。先问清楚“为什么需要这个维度”,比急着调参数或改字段更关键。










