临时表默认用什么引擎?看这个配置项 很多朋友可能都踩过这个坑:用 CREATE TEMPORARY TABLE 创建临时表时,如果不显式指定 ENGINE,它到底会用哪个存储引擎?答案是:它用的是当前会话(Session)的 default_storage_engine 设置值。这里的关键词是“当前
很多朋友可能都踩过这个坑:用 CREATE TEMPORARY TABLE 创建临时表时,如果不显式指定 ENGINE,它到底会用哪个存储引擎?答案是:它用的是当前会话(Session)的 default_storage_engine 设置值。这里的关键词是“当前会话”——它既不是全局默认值,也不是服务器启动时的默认引擎,而是你这条连接生效的那个。
一个常见的误解是:“既然 MySQL 5.6 以后默认引擎就是 InnoDB,那临时表肯定也是 InnoDB 吧?” 结果呢,在一些仍以 MyISAM 为主的老系统里跑复杂查询,就遇到了各种奇怪的问题,根源往往就在这里。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
验证方法其实很简单:执行 SELECT @@session.default_storage_engine; 就能看到当前会话的引擎设置。或者,等临时表创建后,用 SHOW CREATE TABLE <临时表名> 查看(注意:临时表只在创建它的会话中可见,别跑到其他连接里去查)。
InnoDB,那自然没问题。但如果返回的是 MyISAM,那就得留神了——哪怕全局配置已经改成了 InnoDB,只要当前会话里执行过一句 SET SESSION default_storage_engine = 'MyISAM',之后创建的临时表就会乖乖用 MyISAM。CREATE TEMPORARY TABLE t1 (...) ENGINE=InnoDB;。别嫌麻烦,这一行代码能避免后续很多意想不到的麻烦。
为什么说 MyISAM 临时表对处理大结果集特别不友好?问题倒不一定是速度慢,而是它容易直接报错,甚至静默失败。典型的症状包括:ERROR 1169 (23000): Duplicate entry '...' for key 'PRIMARY'(明明表里没定义主键却报主键重复)、ERROR 1034 (HY000): Incorrect key file for table,或者干脆来个 Lost connection to MySQL server during query。
背后的原因很实在:MyISAM 临时表本质上还是依赖磁盘文件(.MYD 数据文件和 .MYI 索引文件),而且它不支持行锁、崩溃恢复和事务回滚。这意味着,一旦查询执行中途被意外终止——比如被人为 KILL、被系统 OOM Killer 干掉,或者磁盘空间不足——那些临时文件就很可能残留下来,或者索引直接损坏。相比之下,InnoDB 的临时表数据存放在共享的临时表空间 ibtmp1(或由 innodb_temp_data_file_path 指定的文件)里,所有操作都受到事务日志的保护。即使进程异常中断,数据也能被干净地清理掉,不会留下“烂摊子”。
tmp_table_size 和 max_heap_table_size 设置得过小,MyISAM 临时文件被写满的风险就很高。ALTER TABLE ... DISABLE KEYS 来加速数据导入?在 MyISAM 临时表上这招可行不通,因为它压根就不支持这个语法。UNION 或者嵌套很深的子查询,MySQL 内部可能会多次创建和销毁临时表。这时,使用 MyISAM 带来的文件 I/O 开销,几乎是呈指数级增长的。既然 MyISAM 临时表有这么多坑,那是不是把 default_storage_engine 改成 InnoDB 就万事大吉了?事情没那么简单。要想确保所有临时表都走上 InnoDB 这条“正道”,还得确认两个关键的配置是否已经放开:
internal_tmp_disk_storage_engine 必须设为 InnoDB(这个参数从 MySQL 8.0.13 开始引入)。它专门控制“当内存不够用时,自动写入磁盘的内部临时表”使用什么引擎。虽然默认值就是 InnoDB,但在一些老版本或者被人手动调整过的环境里,它可能还是 MyISAM。tmp_table_size 和 max_heap_table_size 要设得足够大。这里有个细节:即使你指定了引擎为 InnoDB,如果查询结果集的大小小于这两个参数中较小的那个值,MySQL 仍然会优先使用内存引擎(MEMORY)。只有结果集大小超过了这个内存上限,MySQL 才会将临时表落盘——而这时,它才会真正用到你指定的 ENGINE。POINT, POLYGON)。如果你的查询里用到了 MATCH ... AGAINST 或者空间函数,却强行指定 ENGINE=InnoDB,那就会直接报错。遇到性能问题,别靠猜。最直接的方法是使用 EXPLAIN FORMAT=TREE 或者开启 optimizer_trace 来查看执行计划。不过,这里分享一个更轻量级的排查思路:
可以先开启慢查询日志,并调整相关参数:
SET GLOBAL log_output = 'TABLE'; SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 0;
然后,去查询 mysql.slow_log 表,重点关注 sql_text 字段里有没有出现 CREATE TEMPORARY TABLE 的语句。同时,结合 EXPLAIN 输出结果里是否有 Using temporary 的提示,就能做出基本判断。
还有一个容易被忽略的信号:如果在 SHOW PROCESSLIST 命令的输出里,看到某个连接的状态长时间停留在 Creating tmp table,那基本可以断定它正在使用磁盘临时表,而且可能遇到了瓶颈。 这时候,果断 KILL 掉这个查询,然后去检查临时表的引擎类型,往往比干等着它超时要有用得多。
说到底,临时表的选择,表面上看是存储引擎的差异,本质上却是数据生命周期管理理念的不同——InnoDB 把它当作事务的一部分来严格管理,而 MyISAM 则把它当作普通的磁盘文件,用完可能就随意丢弃了。所以,当你真正要处理 GB 级别的中间结果时,千万别省去 ENGINE=InnoDB 那句声明,它能为你省去大量的维护成本和排查时间。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述