必须将CAST置于SUM()内部,即SUM(CAST(col AS BIGINT)),而非CAST(SUM(col) AS BIGINT),因为溢出发生在累加中间过程,原始列类型决定计算位宽,外层转换无法挽救已发生的溢出。

不是数据太大,而是中间计算类型太小——溢出发生在SUM()执行过程中,不是结果存不下的问题。
SQL Server / MySQL 中 SUM() 报“算术溢出”必须提前 CAST
错误写法 CAST(SUM(col) AS BIGINT) 会失败,因为 SUM(col) 先按原始列类型(如 INT)执行累加,超 2147483647 就直接报错,CAST 根本没机会运行。
- ✅ 正确写法:
SUM(CAST(col AS BIGINT))或SUM(CAST(col AS DECIMAL(18,2))) - ❌ 错误写法:
CAST(SUM(col) AS BIGINT)、CONVERT(BIGINT, SUM(col)) - 对
MONEY类型:优先改用DECIMAL(19,4),避免四舍五入失真 - 在 CTE 或子查询中聚合时,CAST 必须写在内部,外层补救无效
GROUP BY 字符串字段导致内存溢出,加长 VARCHAR 没用
报错 ERROR: string is too long 或 Hash Key overflow 通常不是字段定义太短,而是哈希分组过程内存撑爆。加 ALTER COLUMN ... VARCHAR(10000) 基本白忙。
- 先查真实瓶颈:
EXPLAIN (ANALYZE, BUFFERS)看是否出现Spill to disk或Sort Method: external merge Disk - 验证实际长度:
SELECT MAX(LENGTH(col_name)) FROM table_name,若远小于目标长度,说明问题不在存储层 - 有效解法:用
SUBSTRING(col_name, 1, 200)截断后分组,并确保该长度 ≤ 索引前缀或字段定义上限 - 导出场景:先
STRING_AGG(col_name, ';')聚合成单值,再插入TEXT字段
MySQL 聚合落盘不是参数调得不够,而是 tmp_table_size 和 max_heap_table_size 不一致
临时表写磁盘(Created_tmp_disk_tables 持续上涨)主因是两个关键参数取了较小值,而非 sort_buffer_size 太小——后者只管排序,不管 GROUP BY。
- 必须同时设置:
tmp_table_size = 256M和max_heap_table_size = 256M,并在my.cnf的[mysqld]段中显式声明 - 重启后确认:
SELECT @@tmp_table_size, @@max_heap_table_size,二者数值必须完全相等 - 别盲目设高:超过物理内存 20% 且并发 >30 时,极易触发系统级 OOM
- 更治本:建联合索引覆盖
WHERE + GROUP BY字段,让执行计划避开Using temporary
最常被忽略的是:不同数据库对中间类型的推导规则完全不同——SQL Server 对 SMALLINT 列的 SUM() 仍用 SMALLINT 中间类型,PostgreSQL 对两个 DECIMAL(9,2) 相加可能压缩精度,而这些细节不会出现在错误信息里,只能靠 TYPE_NAME(SUM(col)) 或执行计划反推。

















