导入脚本用 for 循环一条条 insert,一万行跑 96 秒,磁盘 io 一直满。改成批量后同样数据 1.8 秒。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,每条 insert 单独提交就是一次事务,redo 落盘和日志刷写各来一遍,网络往返也按条算。自动提交开着时,一万行就是一万次 fsync。
「批量插入逐条提交」相关的验证我通常做两遍,改完一次、隔天再看一次,确认不是临时生效。日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。
INSERT INTO logs (uid, action, created_at) VALUES (1,'login',NOW()),(2,'pay',NOW()),(3,'logout',NOW()); SET autocommit = 0;
权限不要一口气开到最大,先加到够用再往上试,范围小才好收。把复现步骤压到三条以内,交给同事也能跑出来,才算真的定位清楚。
具体做法是,把循环里的单条 insert 拼成多值 insert 一次五百到一千行;整批放进一个事务 提交一次 出错整批回滚;确认 autocommit 在批处理期间是关的;JDBC 打开 rewriteBatchedStatements 让驱动合并 batch。
最后用这个标准收尾,同样一万行导入时间从 96 秒降到 2 秒左右 磁盘写入曲线变成一段平稳的峰。
