CREATE TEMPORARY TABLE 默认不写 binlog,因 MySQL 将其视为会话本地行为,源码中 check_table_binlog_row_based 函数直接跳过临时表的 binlog 记录路径,确保主从一致性且避免冗余日志。

CREATE TEMPORARY TABLE 为什么默认不写 binlog
因为 MySQL 明确将临时表操作视为会话本地行为,不参与复制和恢复流程,所以 CREATE TEMPORARY TABLE 语句在默认配置下不会写入 binlog —— 这不是 bug,是设计使然。
核心逻辑在源码的 check_table_binlog_row_based 函数里:只要 table->s->tmp_table != NO_TMP_TABLE(即该表是临时表),就直接跳过 binlog 记录路径。哪怕 sql_log_bin = 1、log_bin = ON、binlog_format 是 ROW,也照样不记。
这个机制确保了临时表只在当前连接内存在、自动销毁、不污染主从一致性,尤其在存储过程或复杂查询中频繁建临时表时,避免了大量无意义日志写入。
哪些情况会让 CREATE TEMPORARY TABLE 反而写 binlog
极少数场景下它可能意外进入 binlog,但都属于非标准或高风险配置:
-
binlog_format = STATEMENT且显式设置了log_bin_trust_function_creators = ON,同时该语句出现在函数/存储过程中(但依然不推荐依赖) - 手动执行
SET sql_log_bin = 1后又调用含临时表的 stored procedure,且该 procedure 被标记为SQL SECURITY DEFINER并由高权限用户创建(行为不稳定,版本间差异大) - 使用了某些中间件或代理层,在协议层重写了语句类型,绕过了 MySQL 原生判断逻辑(属外部干扰,非 MySQL 本意)
真实生产环境中,你几乎不会看到 CREATE TEMPORARY TABLE 出现在 binlog events 里。如果看到了,第一反应应该是检查 binlog_format 是否被误设为 STATEMENT,以及是否混用了不兼容的复制配置。
临时表操作不记 binlog 的副作用与注意事项
表面看是“省事”,但有几个关键点容易被忽略:
- 主从架构下,从库不会重建临时表 —— 所以任何依赖临时表存在的后续语句(比如
INSERT INTO t SELECT * FROM tmp)必须保证 tmp 表在从库上也已存在,否则会报Table 'xxx.tmp' doesn't exist -
DROP TEMPORARY TABLE同样不记 binlog,但它只是释放会话资源,不影响数据一致性;真正危险的是把临时表当成“伪永久表”来用 - 如果你在备份脚本里先
SET sql_log_bin = 0,再建临时表,那没问题;但若脚本中途出错没恢复sql_log_bin,后续对**普通表**的 DML 就全静默了 —— 这才是最常踩的坑 - 内部临时表(如 GROUP BY 触发的 MEMORY 表)也不记 binlog,但它的生命周期完全由优化器控制,用户无法干预,和显式
CREATE TEMPORARY TABLE不是一回事
想让临时表操作进 binlog?别试了
MySQL 没提供任何合法、稳定、可维护的方式强制记录 CREATE TEMPORARY TABLE 到 binlog。所有变通方案(比如改用普通表 + 命名规则 + 定时清理)都会破坏临时表的核心价值:自动生命周期管理。
如果你的需求本质是“需要跨会话共享中间结果”,那应该用普通表、分区表、或者物化视图(MySQL 8.0.23+ 的 CREATE MATERIALIZED VIEW);如果只是怕主从不一致,重点应放在业务逻辑层确保临时表使用不跨会话、不跨事务边界。
真正要盯紧的,从来不是“临时表有没有进 binlog”,而是“当前会话的 sql_log_bin 值是不是 1”——它无声无息,却能让你整条链路的变更全部消失。


















