error 1206 根源是 innodb 锁表内存耗尽,非 undo 空间问题;需调大 innodb_lock_table_size 和 innodb_buffer_pool_size,并配合分批操作与索引优化。

这个错误和 Undo 空间没有直接关系——ERROR 1206 (HY000) 的根源是 InnoDB 锁表内存耗尽,不是 Undo 日志满或回滚段不足。混淆它和 Undo log full 或 cannot allocate space in the undo log 是常见误判。
为什么不是 Undo 问题?
InnoDB 的锁信息(行锁、间隙锁、意向锁等)存储在内存中的 lock hash table 里,由 innodb_lock_table_size 控制上限;而 Undo 空间负责事务回滚和 MVCC 版本链,走的是 ibdata1 或独立 undo 表空间(innodb_undo_tablespaces)。两者内存/磁盘路径、分配机制、监控指标完全分离。
典型反证:
- 执行
SELECT ... FOR UPDATE大量无索引扫描时触发ERROR 1206,但SHOW ENGINE INNODB STATUS中UNDO LOG部分显示空闲; - 事务长时间运行导致
Undo log too large报错时,innodb_lock_table_size值往往远未达到上限。
真正该调的参数只有这几个
重点不是调大 Undo,而是让锁能存得下、释放得快:
-
innodb_lock_table_size:直接扩大锁表哈希桶数量,单位是“锁槽”个数(不是字节),默认约 1048576(100 万),可设为2000000或5000000; -
innodb_buffer_pool_size:必须同步调大,因为锁元数据依赖 buffer pool 内存管理,若 buffer pool 过小(如默认 8MB),即使innodb_lock_table_size设得再大也分配失败; -
innodb_buffer_pool_instances:当innodb_buffer_pool_size > 1G时,建议设为 4~8,避免单实例锁竞争加剧; - 别碰
innodb_rollback_segments或innodb_undo_log_truncate——它们影响 Undo,对ERROR 1206无效。
动态修改 vs 配置文件修改
MySQL 5.7.2+ 支持在线调整 innodb_lock_table_size,但有硬限制:
- 必须小于
innodb_buffer_pool_size / 16,否则启动报错或运行时静默截断; - 执行
SET GLOBAL innodb_lock_table_size = 2000000;后,需确认生效:SELECT @@innodb_lock_table_size;; - Windows 下若用
my.ini修改,必须重启服务;Linux 下若用my.cnf,同样需重启才能覆盖动态值; - 注意权限:需要
SYSTEM_VARIABLES_ADMIN权限,普通 DBA 账号常被禁用该权限,报错Access denied时先查SHOW GRANTS;。
业务层必须配合拆分操作
参数调大只是延缓问题,不改 SQL 逻辑迟早还会爆:
- 全表
UPDATE或DELETE必须加WHERE且命中索引,否则 InnoDB 升级为表级锁,锁数量 = 行数 × 锁类型数; - 批量插入用
INSERT ... VALUES (...), (...), ...而非单条循环,减少事务内锁累积; - 用
LIMIT分批处理:例如DELETE FROM t WHERE status=0 LIMIT 10000;,循环执行直到影响行为 0; - 避免长事务:显式
COMMIT后再启新事务,防止锁长期不释放。
最易被忽略的是 buffer pool 和 lock table size 的比例关系——设了 2G 的 innodb_buffer_pool_size 却只配 100 万锁槽,锁表照样溢出;反过来,锁槽设到 500 万但 buffer pool 还是 8MB,MySQL 根本不认这个值。











