根本原因是binlog不记录create temporary table语句,导致从库执行后续引用该表的sql时报错1146。可通过show slave status查看last_sql_error、relay_log_file/pos定位,并解析relay log确认;修复需手动建普通表并替换引用,而非跳过事件;源头应禁用跨语句临时表依赖,改用cte或memory表,统一设row格式。

临时表导致主从同步中断,根本原因不是语法错,而是 binlog 不记录 CREATE TEMPORARY TABLE 语句 —— 从库执行后续引用该表的 SQL(如 INSERT INTO ... SELECT FROM tmp_xxx)时直接报错 1146 Table 'xxx' doesn't exist。
怎么确认是临时表惹的祸
执行 SHOW SLAVE STATUS\G 后重点看三处:
-
Last_SQL_Error是否含"Table 'xxx' doesn't exist",且表名带#sql-、tmp_、__temp等典型临时命名特征 -
Relay_Log_File和Relay_Log_Pos定位出错位置,用mysqlbinlog解析对应 relay log,往前翻几条语句,看有没有CREATE TEMPORARY TABLE - 检查主库
binlog_format:若为STATEMENT,临时表问题更常见;ROW模式虽不记建表语句,但后续 DML 引用仍会失败
修复已发生的同步中断(不能跳过就完事)
设 sql_slave_skip_counter = 1 是危险操作 —— 跳过建表语句后,后面所有依赖该临时表的 INSERT/UPDATE 都会连续报错,可能卡住十几条甚至更多事件。
- 先停复制:
STOP SLAVE; - 在从库手动建一张**普通表**(非临时),建议加
_repl_fix后缀避免冲突,例如:CREATE TABLE tmp_calc_repl_fix LIKE calc_base; - 根据业务逻辑,把原临时表中该有的数据补进去(不能盲目
INSERT SELECT,要确认源数据是否已就绪、是否需过滤) - 修改出错 SQL 中对临时表的引用,全部替换成新普通表名;若需 patch relay log,仅限无 GTID 且紧急场景,风险极高
- 更稳妥做法:用
CHANGE MASTER TO RELAY_LOG_FILE='xxx', RELAY_LOG_POS=yyy跳到出错事件之后的位置再START SLAVE
从源头杜绝临时表进复制链
临时表本身合法,但混入复制流程就是隐患。真正要改的是写法和部署习惯:
- 应用层禁止「创建临时表 → 后续多条语句引用」这种跨语句依赖模式;改用
WITHCTE 替代,例如:WITH tmp AS (SELECT ...) SELECT * FROM tmp JOIN ... - 若必须用内存表,改用
CREATE TABLE ... ENGINE=MEMORY,但需确保从库max_heap_table_size足够,且该表结构在从库也存在 - 运维侧可在主库
my.cnf中配置binlog_ignore_db=tempdb,前提是你能把所有临时逻辑统一挪到名为tempdb的专用库下(注意:replicate-ignore-table=mysql.%对临时表无效) - 最可靠方案:全集群统一设
binlog_format = ROW,并配slave_parallel_workers > 0提升容错与性能
临时表问题最易被忽略的点是:它往往不暴露在日常 DDL/DML 审计里,只有出错时才浮现。真正规范的做法不是等报错再修,而是把「禁止跨语句引用临时表」写进 SQL 开发规范,并在 CI 流程中用正则扫描 SQL 文件拦截 TEMPORARY TABLE + 后续 FROM.*tmp_ 类模式。











