MySQL 8.0 强制临时表使用 InnoDB,显式指定 ENGINE=MyISAM 会报错;InnoDB 临时表参与事务回滚、变量作用域受限、全文索引行为不同、OPTIMIZE TABLE 不释放空间,需针对性调整。

存储过程里用CREATE TEMPORARY TABLE,为什么在InnoDB下报错?
MySQL 5.7 默认允许 MyISAM 临时表,但 MySQL 8.0 强制所有临时表使用 InnoDB 引擎,且要求 tmp_table_size 和 max_heap_table_size 配置足够支撑数据量。若过程里写了 CREATE TEMPORARY TABLE t1 ENGINE=MyISAM ...,升级后直接报错 ERROR 1286 (42000): Unknown storage engine 'MyISAM'(尤其在系统库迁移后禁用 MyISAM 的场景)。
- 实操建议:删掉显式
ENGINE=MyISAM,让 MySQL 自动选引擎;或统一改用ENGINE=InnoDB - 注意
SELECT ... INTO OUTFILE类操作不支持临时表导出,InnoDB 无此能力,需改用常规表 +INSERT ... SELECT+ 清理 - MyISAM 不支持事务,而 InnoDB 下临时表参与事务回滚——若过程含
ROLLBACK,原 MyISAM 临时表数据不会消失,InnoDB 下会清空,逻辑行为已变
SELECT ... INTO @var 在 InnoDB 模式下失效?变量作用域变了
这不是引擎问题,而是 MySQL 8.0 严格模式 + InnoDB 默认事务隔离带来的副作用:用户变量 @var 在语句间传递时,若中间有事务控制(如 START TRANSACTION)、或执行了 DDL(哪怕只是 CREATE TEMPORARY TABLE),部分版本会重置变量作用域。金仓等兼容库更明显——它把变量生命周期绑定到会话级语句块,而非整个存储过程上下文。
- 现象:前一句
SELECT id INTO @last_id FROM log ORDER BY ts DESC LIMIT 1赋值成功,后一句INSERT INTO archive SELECT * FROM log WHERE id > @last_id却插了全表 - 原因:
@last_id实际为NULL,因中间隐式提交或解析器提前释放了变量 - 解法:改用声明式变量
DECLARE last_id BIGINT DEFAULT 0;+SELECT id INTO last_id FROM ...,确保作用域可控
MyISAM 表上的全文索引迁到 InnoDB 后,MATCH ... AGAINST 结果不对
InnoDB 的全文索引实现和 MyISAM 完全不同:分词器默认不支持中文(需配置 ngram 插件),停用词列表更严格,最小词长默认为 3(MyISAM 是 4),而且不支持布尔模式下的 * 截断语法(如 'abc*')。
- 检查当前配置:
SHOW VARIABLES LIKE 'innodb_ft_%';,重点关注innodb_ft_min_token_size和innodb_ft_enable_stopword - 重建索引前先设好参数:
SET GLOBAL innodb_ft_min_token_size = 2;,再ALTER TABLE article DROP INDEX ft_title, ADD FULLTEXT INDEX ft_title(title) - MyISAM 支持
WITH QUERY EXPANSION,InnoDB 不支持,相关查询需重写
存储过程中调用 OPTIMIZE TABLE,InnoDB 下变成“假动作”
MyISAM 的 OPTIMIZE TABLE 真的会重建表、回收碎片;InnoDB 的同名命令实际只做 ANALYZE TABLE + 可选的在线 DDL(取决于 innodb_defragment 等开关),不释放磁盘空间。如果过程里靠它“瘦身”来缓解主从延迟或磁盘告警,升级后就失效了。
- 替代方案:用
ALTER TABLE tbl_name ENGINE=InnoDB强制重建(需足够磁盘空间) - 或启用
innodb_file_per_table=ON+innodb_defragment=ON,让后台自动整理 - 注意:该语句在存储过程中执行会隐式提交事务,破坏原有事务边界——这是比功能弱化更隐蔽的风险
真正卡住迁移的,往往不是语法报错,而是这些“看起来跑通了,但结果不对”的行为偏移。尤其是涉及临时表、变量、全文检索和维护命令的地方,引擎切换只是表象,底层事务模型和执行器策略已经换了底子。










