MySQL 5.7 的报表库每小时磁盘写入二十 G,iostat 里写占比很高,Created_tmp_disk_tables 一小时涨了几十万,慢查询里全是带 group by 的统计语句。
这类报错背后常见的原因有几处,逐个排除就行。tmp_table_size 和 max_heap_table_size 都只有 16M,稍大的结果集就落盘;统计语句里有 text 和 blob 字段,内存临时表不允许存这类类型;group by 的列没有索引,需要建临时表做聚合;并发报表太多,每个连接各建一份临时表,磁盘被打满。
上来先看磁盘临时表的增长量
mysql -e "show global status like 'Created_tmp%'"
随后把两个内存临时表上限同步调大
mysql -e "set global tmp_table_size=268435456; set global max_heap_table_size=268435456"
再往下写进配置并确认落盘路径
printf '[mysqld]\ntmp_table_size=256M\nmax_heap_table_size=256M\ntmpdir=/data/mysqltmp\n' > /etc/my.cnf.d/tmp.cnf
补索引让聚合少建临时表
mysql -e "explain select shop_id,count(*) from orders group by shop_id"
恢复的判定其实很直接。Created_tmp_disk_tables 的增速下降到原来的十分之一以内,磁盘写明显回落,报表查询耗时缩短。
内存临时表上限两个参数必须一起改,取较小值生效;带 blob 的查询一定会落盘,这类语句更适合放到从库或离线库跑。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。
