前言
最近导入数据库遇到一件特别反直觉的怪事:170M的SQL导入稳稳成功,一个27M的小文件,phpMyAdmin直接502 。 排查半天,不是上传大小限制,也不是服务器带宽问题,而是SQL语句结构踩了坑。后续改用MySQL的source命令导入,又遇到新麻烦:疯狂打印Query OK,1 row affected,跑的极慢,按Ctrl+C还停不下来,折腾很久才搞定。把踩坑过程整理出来。
一、为什么27M小文件phpMyAdmin直接502,170M大文件反而没事?
很多人会下意识觉得文件越大越容易报错,这次完全反过来。
phpMyAdmin的导入逻辑,是PHP脚本读取SQL,在PHP层做语句切割、分词,循环和MySQL通信执行。
- 170M的备份:导出时开启了
extended-insert,一条INSERT一次性写入上千行数据。SQL语句总量少,PHP循环次数不多,在超时时间内跑完,顺利导入。 - 27M这个文件:导出参数是一行一条INSERT。文件体积不大,但里面几十万条独立Insert语句。PHP循环几十万次去解析、调用数据库,累积耗时超过php-fpm的
request_terminate_timeout,php-fpm直接终止进程,页面返回502 Bad Gateway。
划重点:phpMyAdmin导入瓶颈不在文件大小,而在SQL语句数量。上传大小只是第一道门槛,大量单行INSERT才是隐形杀手。
二、source基础用法
网页导入踩坑之后,自然想到直接用MySQL自带source命令,绕开PHP,从数据库客户端直接读取文件。
两种常用写法:
-
shell管道方式,适合简单场景,缺点是报错信息不直观
mysql -u账号 -p库名 < /tmp/demo.sql
注意坑:
-p后面不要加空格写密码,很容易报访问拒绝。
-
交互式source(推荐,方便看报错,排查问题首选)
#登录mysql客户端
mysql -uroot -p
#切换目标数据库
use test_db;
#执行导入
source /tmp/demo.sql;
三、source导入速度翻倍的关键参数(必加)
默认情况下,MySQL执行完每一条INSERT就提交事务、刷磁盘。 几十万条单独INSERT,就会几十万次磁盘写入,IO直接拉满,屏幕不停刷Query OK,1 row affected,慢到难以忍受。
导入前先执行下面这几句,攒全部数据最后一次性提交,速度提升几十倍
--关闭自动提交
SET autocommit=0;
--临时关闭唯一索引校验
SET unique_checks=0;
--临时关闭外键约束检查
SET foreign_key_checks=0;
-- 如果不需要主从复制,可以临时关闭binlog,主从环境不要开启
-- SET sql_log_bin = 0;
--执行导入
source /tmp/demo.sql;
--全部导入完成,一次性提交事务
COMMIT;
--恢复数据库原有配置,别忘记!
SET autocommit=1;
SET unique_checks=1;
SET foreign_key_checks=1;
-- SET sql_log_bin = 1;
⚠️重要提醒:这套语句必须从头一次性执行,不要导入到一半才去关闭autocommit,会造成事务错乱。
四、头疼问题:source跑起来Ctrl+C停不住怎么办?
很多人踩这个坑:按Ctrl+C只能终止当前这一条SQL,source会继续读取后面文件接着跑,没法一次性停止整个导入脚本。
正确停止方案:
-
新开一个SSH窗口登录服务器,不要关掉正在跑导入的终端
-
登录mysql,查询当前所有数据库连接
SHOW PROCESSLIST;
找到你导入对应的会话,看Host是你的SSHIP,Command为Query,记下Id。 3. 执行kill断开会话,导入立刻终止
KILL 查到的进程ID;
补充提醒: 如果没有提前设置autocommit=0 ,每一行INSERT执行完就已经提交写入磁盘。就算kill断开,已经跑完的数据不会自动回滚。后续重新导入前,记得执行TRUNCATE TABLE 表名;清空表,防止重复数据。
应急简单办法:直接关闭当前SSH标签页,连接断开,导入终止。
五、导出备份的最佳实践,从源头避免导入慢
mysqldump导出的时候,默认开启--extended-insert,多条数据合并到一条INSERT,备份文件更小,导入速度快很多。 推荐导出命令:
mysqldump -u账号 -p数据库名 --extended-insert=1 > dump.sql
--extended-insert=1:合并多行,批量写入,推荐--extended-insert=0:一行一条INSERT,就是本次踩坑的慢模式
总结
- phpMyAdmin导入的瓶颈是PHP解析SQL,不是文件体积。大量单行INSERT很容易触发php-fpm超时,出现502;
- SQL文件超过10M,优先用MySQL source导入,绕开PHP层限制;
- source导入一定要搭配关闭autocommit、外键、唯一校验,批量提交,大幅降低磁盘IO;
- source运行时Ctrl+C无法整体终止,新开窗口KILL进程才是正确操作;
- mysqldump导出尽量开启extended-insert,减少SQL语句数量,后续导入省心。
个人习惯:现在只要是大数据库备份,一律放弃phpMyAdmin网页导入,直接服务器端source。
这个内容可以改成更贴近真实踩坑笔记的风格,工作任务模式能帮你打磨开篇、调整段落语感,还可以补充配图建议,要不要用它继续?