MySQL内存临时表大小取tmp_table_size与max_heap_table_size的较小值,二者必须设为相同值(如64M~256M),否则易触发磁盘临时表导致IO瓶颈;同时需规避TEXT/BLOB字段、函数内临时表及sort_buffer_size过大引发的OOM风险。

tmp_table_size 和 max_heap_table_size 设置过小
当查询中出现 GROUP BY、ORDER BY、子查询或派生表(derived table)时,MySQL 会先尝试在内存中创建临时表。如果结果集超过 tmp_table_size 或 max_heap_table_size 中的较小值,就会自动降级为磁盘临时表(MyISAM 或 InnoDB 引擎),触发大量随机 IO,成为并发瓶颈。
常见现象是:单条查询响应尚可,但 20+ 并发时 QPS 断崖下跌、Created_tmp_disk_tables 指标飙升、磁盘 %util 接近 100%。
-
tmp_table_size和max_heap_table_size必须设为相同值,否则以小者为准 - 线上建议从
64M起步,大查询场景直接设为256M(需预留足够物理内存) - 不要只调大
tmp_table_size而忽略max_heap_table_size,后者还控制用户显式创建的MEMORY表上限
函数内联执行导致临时表无法复用
MySQL 函数(尤其是 DETERMINISTIC 函数)在被多次调用时,并不会缓存中间临时表结构或数据。每次调用都重新分配内存、构造临时表、写入数据、排序/分组、再销毁——这个过程无法跨会话或跨调用共享。
更麻烦的是:如果函数里嵌套了 SELECT ... INTO TEMPORARY TABLE 或隐式派生表(如 (SELECT ...) 子查询),每次调用都会触发一次完整生命周期,高并发下极易打满内存或触发 swap。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 避免在函数体中显式创建临时表;改用普通表 + 唯一前缀模拟,或改由应用层缓存结果
- 检查函数是否真需要
DETERMINISTIC属性;若内部含NOW()、RAND()或查表逻辑,应改为NO SQL或READS SQL DATA,避免优化器误判 - 用
EXPLAIN FORMAT=JSON查看函数调用后的执行计划,确认是否有"using_temporary_table": true字段
sort_buffer_size 是 per-connection 参数,放大内存压力
每个连接在执行排序操作时,都会独立分配 sort_buffer_size 内存。函数中若含 ORDER BY,且并发连接数达数百,总内存开销 = 连接数 × sort_buffer_size。设为 2M 时,500 个连接就吃掉 1GB,极易触发 OOM Killer。
注意它和 tmp_table_size 不同:后者是“单次临时表上限”,而 sort_buffer_size 是“每连接每次排序独占内存”。
- 线上建议设为
2M–4M,绝不要设成32M级别(除非确认极少并发) - 优先优化 SQL 让排序走索引(
type为range或ref),而非堆内存 - 监控状态变量:
Sort_merge_passes持续上升,说明排序频繁落盘,必须干预
临时表引擎切换引发锁与日志开销
当内存临时表溢出到磁盘时,MySQL 默认使用 MyISAM(5.7 及以前)或 InnoDB(8.0+)引擎。前者无事务、但有表级锁;后者支持事务,却带来额外 redo log 和 doublewrite 开销。无论哪种,都比纯内存操作慢 10–100 倍。
更隐蔽的问题是:多个并发函数调用同时写同一个磁盘临时表名(MySQL 自动生成),可能触发引擎层锁竞争或文件系统锁,尤其在 ext4/xfs 的 directory entry 锁上卡住。
- 用
SHOW GLOBAL STATUS LIKE 'Created_tmp%';实时观察Created_tmp_disk_tables/Created_tmp_tables比值,> 10% 就该警觉 - 禁止在函数中使用
CREATE TEMPORARY TABLE;临时表应由调用方显式管理生命周期 - 若必须用磁盘临时表,确保
tmpdir挂载在 SSD 上,且不与数据目录共用同一块盘


















