会,CREATE TEMPORARY TABLE默认触发MDL读锁,因需校验同名普通表、权限及字符集兼容性;该锁绑定会话事务生命周期,未提交或错误未回滚将长期持锁,高并发下同名临时表密集创建更易引发MDL争抢。

临时表创建会触发元数据锁(MDL)吗?
会,而且是默认行为。MySQL 在执行 CREATE TEMPORARY TABLE 时,必须先对目标表名做解析和校验——哪怕只是临时表,也要检查同名普通表是否存在、当前用户是否有权限、字符集是否兼容等。这个过程需要申请该表名对应对象的 MDL 读锁(MDL_SHARED),防止并发 DDL(如 DROP TABLE 或 RENAME TABLE)中途篡改结构。
关键点在于:这个 MDL 锁的生命周期绑定到**当前会话事务**,不是语句级。如果存储过程中开启了事务但没显式提交,或者语句出错后未回滚,MDL 锁就一直挂着,后续所有涉及同名(哪怕是不同会话的临时表)或同库下相关操作都可能被阻塞。
为什么“同名临时表”也会引发锁等待?
临时表虽是会话级隔离,但 MySQL 解析器在遇到 tmp_orders 这类名字时,并不会立刻认定它是临时表;它会先查 information_schema.TABLES 和基表字典,确认无同名普通表后才走临时表路径。高并发下,大量会话同时执行带 IF NOT EXISTS 的 CREATE TEMPORARY TABLE tmp_orders,就会密集争抢对 tmp_orders 这个名字的 MDL 元数据读锁,尤其当 information_schema 查询本身因锁或统计延迟变慢时,排队效应更明显。
-
SHOW CREATE TABLE tmp_orders会报错(临时表不可见),但SELECT * FROM information_schema.COLUMNS WHERE TABLE_NAME = 'tmp_orders'却能查到——说明解析层确实在查字典 - 避免用
IF NOT EXISTS+ 临时表组合;改用先DROP TEMPORARY TABLE IF EXISTS tmp_orders,再无条件CREATE TEMPORARY TABLE tmp_orders - 别在循环里反复建同名临时表;建一次,重复
TRUNCATE或重插即可
哪些操作会让临时表锁问题更严重?
真正放大竞争的不是建表动作本身,而是它和其他隐式行为的叠加:
- 存储过程内用了
START TRANSACTION但没配对COMMIT或ROLLBACK→ MDL 锁卡在整个事务周期内 - 临时表
SELECT ... INTO OUTFILE或INSERT SELECT源自基表且未走索引 → 基表被加意向锁(IX),进一步拖慢其他 DML - 错误处理缺失:某条
INSERT INTO tmp_orders因字段不匹配失败,但后续逻辑仍试图SELECT它 → 会话卡在等待自己持有的 MDL 锁释放 - 连接池复用场景下,上一个请求留下的未清理临时表+未结束事务,直接污染下一个请求的执行环境
怎么确认真是临时表引发的 MDL 竞争?
别猜,用三组命令交叉验证:
- 看阻塞源头:
SELECT * FROM information_schema.INNODB_TRX WHERE TRX_STATE = 'RUNNING' AND TRX_QUERY LIKE '%TEMPORARY%' - 看锁等待链:
SELECT * FROM performance_schema.data_lock_waits(MySQL 8.0+)或SHOW ENGINE INNODB STATUS\G里搜temp和MDL - 看进程状态:
SHOW FULL PROCESSLIST中State为Waiting for table metadata lock且Info字段含CREATE TEMPORARY或DROP TEMPORARY
最常被忽略的一点:临时表本身不持久,但它的创建动作会留下元数据痕迹,而这些痕迹在事务未结束前,就是一把实打实的 MDL 锁。修复不在“怎么建更快”,而在“建完立刻收尾、出错必须兜底”。











