MySQL批量执行SQL文件卡住的本质是单个客户端串行执行,遇大事务、锁等待或语法错误即阻塞后续;需预检查、分片、显式错误处理及慢日志分析定位真实瓶颈。
MySQL批量执行SQL文件时为什么卡在某个文件不动了
本质是单个 mysql 客户端进程串行读取并执行,遇到大事务、锁等待或语法错误会阻塞后续所有文件。不是“批量”本身慢,而是缺乏失败隔离和进度反馈。
- 默认用
mysql -u root -p 执行单文件;多个文件必须靠 shell 循环,但任一文件出错(比如ERROR 1062 (23000): Duplicate entry)会导致整个流程中断 - 大
.sql文件(尤其含百万级INSERT)若未拆分事务,会撑爆innodb_log_file_size或触发锁升级,表现为 CPU 低、IO 高、SHOW PROCESSLIST显示updating卡住 - 别直接用
source在交互式客户端里批量执行——它不支持变量替换、无超时控制,且错误堆栈难定位
如何安全地循环执行多个SQL文件(bash + mysql命令组合)
核心思路:每个文件独立进程、捕获退出码、记录日志、跳过失败项(可选)。
- 用
for f in *.sql; do mysql -u root -p$PASS db_name > exec.log 2>&1 || echo "FAIL: $f" >> exec.log; done - 关键点:
||后必须跟明确动作,否则失败后仍继续;$PASS要提前设好,避免交互式输密码导致卡住 - 加
--force参数可让 mysql 忽略非致命错误(如重复建表),但会掩盖真实问题,慎用;真正需要的是预检查——比如先用grep -q "CREATE TABLE" "$f"判断是否建表语句,再决定是否加DROP TABLE IF EXISTS - 大文件务必提前用
split -l 5000 big.sql chunk_拆分,并在每段开头加SET autocommit=0;,结尾加COMMIT;
为什么用 mysqlimport 或 LOAD DATA INFILE 比 source 快十倍
因为绕过了 SQL 解析层,直接写入存储引擎缓冲区。但只适用于纯数据导入(CSV/TSV),不支持 DDL 或逻辑判断。
-
mysqlimport本质是LOAD DATA INFILE的命令行封装,要求文件在数据库服务器本地(或启用local_infile=ON并用LOAD DATA LOCAL INFILE) - 字段分隔符必须显式指定:
mysqlimport --fields-terminated-by=',' --lines-terminated-by='\n' db_name data.csv - 常见坑:
ERROR 1148 (42000): The used command is not allowed with this MySQL version→ 检查服务端local_infile变量和客户端是否加--local-infile=1 - 字符集容易错乱:
--default-character-set=utf8mb4必须和服务端character_set_database一致,否则中文变???
可视化分析执行瓶颈只能靠 slow log + pt-query-digest
phpMyAdmin 或 Navicat 的“执行时间”只显示客户端耗时,无法反映锁竞争、磁盘 IO 等真实瓶颈。
- 先开慢日志:
SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1;,日志路径看slow_query_log_file变量 - 用 Percona Toolkit 的
pt-query-digest /var/lib/mysql/slow.log输出报告,重点关注Rank列和Query_time中的p95值 - 如果某类
INSERT ... SELECT占比高,说明没走索引或临时表太大;此时应检查EXPLAIN FORMAT=TREE输出,而非盲目调innodb_buffer_pool_size - 注意:开启慢日志有性能损耗,生产环境建议仅在问题复现期开启,且用
log_queries_not_using_indexes=OFF避免日志爆炸
真正麻烦的从来不是“怎么批量执行”,而是每个 SQL 文件内部的事务边界、索引状态、字符集声明是否统一。这些细节不会报错,但会让同样一套脚本在测试库飞快、在线上库寸步难行。










