前些日子有个需求就是要将sql server数据库迁移到mysql,单表数据量在千万级。因mysql已经是线上运行库且两库之间表结构不完全相同,所以要在尽可能短的时间将数据导入,最终选用了如下方案。
sql server
1、在sql server数据库建立mysql表对应视图
2、用sql server BCP(帮助文档) 通过视图生成csv文件,这里有两点需要注意
a、BCP不支持utf-8编码
c、列分隔符和行分隔符对导出内容必须是唯一的
b、生成csv文件不要大于2G,对于大数据集可以分段导出如下面的第二条命令
bcp "SELECT * database.dbo.v_user" queryout d:\user.csv -c -t [c:@] -r [l:@]\n -T
bcp "SELECT * FROM database.dbo.v_subscription ORDER BY id" queryout d:\subscription1k0.csv -c -F 1 -L 5000000 -t , -r \n -T
bcp "SELECT * FROM database.dbo.v_subscription ORDER BY id" queryout d:\subscription1k0.csv -c -F 1 -L 5000000 -t , -r \n -T
3、上传csv文件到mysql数据库服务器,你可以下载安装winscp来完成这件事情。如果觉得文件太大你也可以先压缩再上传哦。
set scpshell=d:\winscp.txt
echo option confirm off > %scpshell%
echo open user:password@192.168.0.234:22 >> %scpshell%
forfiles /P D:\ /M *.csv /C "cmd /c echo put @path /home/huangjh/@file >> %scpshell%
echo close >> %scpshell%
echo exit >> %scpshell%
"C:\Program Files (x86)"\WinSCP\WinSCP /console /script=%scpshell%
echo option confirm off > %scpshell%
echo open user:password@192.168.0.234:22 >> %scpshell%
forfiles /P D:\ /M *.csv /C "cmd /c echo put @path /home/huangjh/@file >> %scpshell%
echo close >> %scpshell%
echo exit >> %scpshell%
"C:\Program Files (x86)"\WinSCP\WinSCP /console /script=%scpshell%
至此数据库导出工作就算完成了,如果愿意你可以将以上操作写成一个批处理脚一次完成。
mysql
1、用 iconv对上传上来的csv进行转码,因为我的mysql库是utf8编码。
find /home/le -maxdepth 1 -name "*.csv" -exec iconv -f GB18030 -t UTF-8 -c {} -o /tmp/{} \;
2、用shell将csv数据导入mysql数据库。
/usr/local/mysql/bin/mysql -u user -p password <<EOF
USE database;
LOAD DATA INFILE '/tmp/user.csv' INTO TABLE user FIELDS TERMINATED BY '[c:@]' LINES TERMINATED BY '[l:@]\r\n';
EOF
USE database;
LOAD DATA INFILE '/tmp/user.csv' INTO TABLE user FIELDS TERMINATED BY '[c:@]' LINES TERMINATED BY '[l:@]\r\n';
EOF
到这里整个导入导出就算完成了,但这种导入对做了mysql复制的数据库就得注意了它不会产生日志故不能同步数据到从库。一种比较笨的办法就是做个中间库跳转下用以下命令再从中间库导出导入。
#导出
/usr/local/mysql/bin/mysqldump -t -e --add-locks=false 数据库名 user -u 用户名 -p密码 > /tmp/user.sql
#导入
/usr/local/mysql/bin/mysql -u 用户名 -p密码 数据库名 < /tmp/user.sql
/usr/local/mysql/bin/mysqldump -t -e --add-locks=false 数据库名 user -u 用户名 -p密码 > /tmp/user.sql
#导入
/usr/local/mysql/bin/mysql -u 用户名 -p密码 数据库名 < /tmp/user.sql
最终导出导入时我们应该在两台服务器上各写一个完整脚本来执行以免手误。