背景
事故背景
因为运维人员的失误,误将生产数据库清空了,幸好操作前做了备份,但38G的超大sql文件导入耗时将近1个小时,还出现了两次导入失败,其中一次导入进度约等于99%时发生了主键冲突而停止,几乎浪费了3个多小时的宝贵时间,虽然最终还原完成上线成功,但对于这种超大数据库文件的导入确实欠缺应对策略,故此复现问题。
首先数据还原中文件导入至99%时发生了唯一索引冲突造成了导入停止,定位发现有一程序仍在运行插入数据,因此可行的情况下,将服务停止再做还原,另外导入的方式,直接使用mysql导入遇到错误会终止,而source导入方式遇到错误会继续,很不幸运维人员使用的mysql命令进行导入的,导入错误提示为37000行左右,假设不想再浪费一个小时的时间,如何解决冲突如何继续导入呢?
思路,首先定位文件总行数,然后根据出错行数将剩余部分截取至新文件中,删除冲突的sql行,使用source继续进行导入。
数据准备
文件大小:39GB, 行数:38912行, 每行:约1MB字符, 文件名称:bigtext.txt。
行数统计
wc -l 文件名称
grep -c '\n' 文件名称
#其他不建议
sed -n '$=' 文件名称
awk 'END { print NR }' 文件名称
效率对比
time wc -l bigtext.txt
38912 bigtext.txt
real 9m58.965s
user 0m9.455s
sys 0m50.827s
time grep -c '\n' bigtext.txt
38912
real 5m22.045s
user 0m11.758s
sys 0m16.724s
#sed awk 时间过长,未作统计
结论 建议使用grep -c的方式统计行数
文件截取
#从结尾截取文件
tail -c 字符大小 文件名称 > 新文件名称
tail -n 行数 文件名称 > 新文件名称
#从开头截取文件
head -c 字符大小 文件名称 > 新文件名称
head -n 行数 文件名称 > 新文件名称
数据导入
#mysql导入
mysql -uusername -ppassword scheme < scheme.sql
#source导入
mysql -uusername -ppassword
> source import.sql
区别 mysql遇到错误会终止,source遇到错误会继续
加速导入
未作详细验证,感觉实际影响并不大
set sql_log_bin=off;
set autocommit=0;
start transaction;
source 文件.sql;
commit;
#改回配置
set sql_log_bin=on;
set autocommit=1;
#其他加速配置
# 进入mysql中执行如下
SET GLOBAL foreign_key_checks=0;
SET GLOBAL unique_checks=0;
SET GLOBAL innodb_flush_log_at_trx_commit=0;
SET GLOBAL sync_binlog=0;
-- 你的sql语句
SET GLOBAL foreign_key_checks=1;
SET GLOBAL unique_checks=1;
SET GLOBAL innodb_flush_log_at_trx_commit=1;
SET GLOBAL sync_binlog=1;
还是要根据实际情况正确处理问题,生产无小事。