必须盯死type、key、Extra三列:type为ALL或index说明未走有效索引,key为NULL表示完全未用索引,Extra出现Using temporary或Using filesort则触发临时表与文件排序,极易爆内存。

GROUP BY执行计划里哪三列必须盯死
执行计划里type、key、Extra这三列直接决定分组会不会爆内存。type是ALL或index,说明没走有效索引;key为NULL,等于完全没用索引;Extra里一旦出现Using temporary或Using filesort,就是MySQL被迫建临时表+排序——哪怕数据才百万级,一落盘就卡住。
联合索引字段顺序必须和GROUP BY严格一致
不是把所有分组字段塞进索引就行。GROUP BY user_id, status,就得建INDEX idx_group (user_id, status);反过来建(status, user_id)基本无效。MySQL只认最左前缀,且分组阶段要按字段顺序逐层哈希或排序。如果还有WHERE条件,比如WHERE status = 'active',优先把过滤性强的字段放前面:INDEX idx_where_group (status, user_id)比(user_id, status)更稳。
避免在GROUP BY字段上套函数
GROUP BY DATE(created_at)会让整个索引失效。改用冗余日期字段(如date_part)加范围查询更可靠。同理,UPPER(name)、CONCAT(a, b)这类操作也会导致索引无法命中,分组直接退化成全表扫描+临时表。
tmp_table_size不够时临时表会悄悄落盘
MySQL默认把小临时表放内存,超限就写磁盘成MyISAM临时表。SHOW PROCESSLIST里看到Copied to tmp table on disk就是信号——I/O拖垮性能的开始。可调大tmp_table_size和max_heap_table_size,但别盲目堆内存;更关键的是先让Extra里出现Using index,说明只读索引不回表,再配合key非NULL才算真正生效。
key_len值是否对得上:比如VARCHAR(255)字段实际只用前10字符,key_len应≈30(utf8mb4下每字符占4字节),若显示765,说明索引定义和查询条件长度不匹配——这种细节错一点,索引就白建。


















