select ... into outfile 本身不直接触发表级锁,但在 myisam 上隐式加读锁,innodb 中若处于事务或配合 lock tables 则可能阻塞写入;mysqldump 的 --single-transaction 对纯 innodb 有效,但遇 myisam 会退化为全局读锁;mysqlpump 更适合混合引擎且支持无锁导出,但仍需注意资源争用与版本兼容性。
导出时 select ... into outfile 触发表级锁?
mysql 5.7 及更早版本中,select ... into outfile 在 myisam 表上会隐式加读锁,innodb 表虽不锁表,但若配合 lock tables 或事务未提交,仍可能阻塞写入。本质不是导出命令本身锁表,而是它常被放在显式事务或管理脚本里,顺带拖垮了并发。
- 确认是否在事务中执行:检查脚本里有没有
BEGIN/START TRANSACTION且未及时COMMIT - 避免对大表直接
SELECT ... INTO OUTFILE:哪怕 InnoDB,全表扫描 + 磁盘 I/O 也会拉高innodb_row_lock_time - 用
SHOW PROCESSLIST查看长时间Sending data状态的线程,大概率是它卡住了其他写操作
mysqldump 加 --single-transaction 还锁表?
--single-transaction 对 InnoDB 有效,靠一致性快照避免锁表;但一旦库中混有 MyISAM 表,mysqldump 会自动退化为加全局读锁(FLUSH TABLES WITH READ LOCK),整个实例写入就停了。
- 先查存储引擎:
SELECT table_name, engine FROM information_schema.tables WHERE table_schema = 'your_db'; - 若有 MyISAM 表,要么提前转成 InnoDB(
ALTER TABLE t ENGINE=InnoDB;),要么改用--lock-tables=false+ 手动确保无写入(风险自担) -
--single-transaction不适用于 RDS 只读实例或开启了read_only=ON的主库——会报错Cannot execute statement in a read-only transaction
真正无锁:用 mysqlpump 替代 mysqldump?
mysqlpump(MySQL 5.7+ 自带)默认按表并行导出,每张表单独开启事务,天然支持 --skip-lock-tables,且对混合引擎更宽容。但它不是“完全无影响”——高并发导出仍抢 CPU 和磁盘带宽,线上务必限速。
- 强制单线程、限速导出:
mysqlpump --single-transaction --default-parallelism=1 --compress-output=LZ4 your_db --exclude-tables=logs_2023* > dump.sql - 排除大日志表可大幅缩短导出时间,
--exclude-tables支持通配符,比mysqldump --ignore-table更灵活 - 注意
mysqlpump不兼容 MySQL 5.6,RDS 部分旧版本也不带,执行前先跑mysqlpump --version
低峰期也卡?检查 max_allowed_packet 和磁盘 IO
导出失败未必是锁,常见假象是:进程看似在运行,实际卡在写临时文件或网络缓冲区。比如 mysqldump 遇到超长字段,反复重试导致连接堆积;或导出目标路径在慢盘(如 NFS),写入延迟引发客户端超时重连,间接推高锁等待。
- 服务端调大
max_allowed_packet(至少 256M),客户端也要同步设(mysqldump --max-allowed-packet=268435456) - 导出路径必须本地 SSD,禁用
/tmp(可能空间小或挂载为 noexec);用df -h和iostat -x 1实时盯盘 - 如果走网络导出(如
mysqldump | gzip | ssh),管道任一环节阻塞都会让 mysqldump 挂起,进而 hold 住事务——优先落地本地再传
锁表问题背后,往往是导出动作和业务负载共享同一套资源边界。没做资源隔离的“低峰期”,可能只是你没看见后台的定时任务、监控采集或备份轮转正在啃磁盘。











