MySQL大数据迁移备份
MySQL迁移通常使用的有三种方法:
1、数据库直接导出,拷贝文件到新服务器,在新服务器上导入。
2、使用第三方迁移工具。
3、数据文件和库表结构文件直接拷贝到新服务器,挂载到同样配置的MySQL服务下。
第一种方案的优点:会重建数据文件,减少数据文件的占用空间,兼容性最好,导出导入很少发生问题,需求灵活。缺点:使用传统导出导入时间占用长。
第二种方案的优点:设置完成后传输无人值守,自动完成。缺点:不够灵活,设置繁琐,传输时间长,异常后很难从异常的位置继续传输。
第三种方案的优点:时间占用短,文件可断点传输,操作步骤少。缺点:新旧服务器中MySQL版本及配置必须相同,可能引起未知问题。
假如数据库迁移是因为业务瓶颈或项目改造等需要变动数据表结构的(比如分区分表),我们便只能使用第一种方法了。
操作一:本文总结各种场景下的数据复制、迁移、转换。
1、导入、导出
利用mysqldump命令将数据文件导出成一个文本文件,这在不同场景下具有更高的安全性。如:表引擎改变。
数据导出:mysqldump -uroot -p dbname > dbname.sql (包含表结构和表数据)
数据导入:mysql -uroot -p dbname < dbname.sql
注意:导出的sql文件包含旧表信息,请修改其中的create table语句。在create之前会有一个DROP table 操作。如果没有注意到这点,原数据就会被删除。这种情况可以用下列的sql操作:
只导出:数据:mysqldump -uroot -p -t dbname > dbname.sql
只导出表结构:mysqldump -uroot -p -d dbname > dbname.sql
2、将一张表的数据转换到另一张表、并且更新表结构
a、以下sql适用于小量数据,速度快。
- mysql>create table innodb_table like myisam_table;
- mysql>alter table innodb_table engine=innodb;
- mysql>insert into innodb_table select * from myisam_table;
b、更高效的办法是增量的填充表,在填充每个增量数据块时都提交事务,这样就不会导致撤销日志过大,假设id是主键,可以重复运行一下查询(每次逐渐增大x和y值)直到所有数据都复制到新表。
- mysql>start transaction;
- mysql>insert into innodb_table select * from myisam_table where id between x and y;
- mysql>commit;
转移操作完成后,源表仍会保留,可以在完成操作后DROP它,注意:如有必要,在转换时加锁源表,防止在转换时数据不一致。
操作二:使用MySQL的SELECT INTO OUTFILE 、LOAD DATA INFILE快速导出导入数据
LOAD DATA INFILE语句从一个文本文件中以很高的速度读入一个表中。MySQL官方文档也说明了,该方法比一次性插入一条数据性能快20倍。
当用户一前一后地使用SELECT ... INTO OUTFILE 和LOAD DATA INFILE 将数据从一个数据库写到一个文件中,然后再从文件中将它读入数据库中时,两个命令的字段和行处理选项必须匹配。否则,LOAD DATA INFILE 将不能正确地解释文件内容。
下面是一个项目的例子,MySQL由windows平台迁移到Linux平台,数据总量12G
导出到文件中(select into outfile)
SELECT fields INTO OUTFILE 'file_name'
[{FIELDS | COLUMNS} 字段
[TERMINATED BY 'string'] 字段之间分隔符号
[[OPTIONALLY] ENCLOSED BY 'char'] 字段被包含在char中间
[ESCAPED BY 'char'] 忽略字段里出现的char
]
[LINES
[STARTING BY 'string'] 忽略开头是string的行
[TERMINATED BY 'string'] 行分隔符
]
FROM test_table;
导入文件中的数据到mysql表
LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name'
[REPLACE | IGNORE] 遇到重复的时候处理方法,替换或者是忽略
INTO TABLE tbl_name 导入数据的目的表名
[PARTITION (partition_name,...)] 分区选择
[CHARACTER SET charset_name] 字符集
[{FIELDS | COLUMNS} 字段
[TERMINATED BY 'string'] 字段之间分隔符号
[[OPTIONALLY] ENCLOSED BY 'char'] 字段被包含在char中间
[ESCAPED BY 'char'] 忽略字段里出现的char
]
[LINES
[STARTING BY 'string'] 忽略开头是string的行
[TERMINATED BY 'string'] 行分隔符
]
[IGNORE number {LINES | ROWS}] 忽略行/列
[(col_name_or_user_var,...)] 目的表的表字段名或者用户变量名
[SET col_name = expr,...] 设置表字段值
Windows平台导出数据:
tables.txt是保存数据表名称的文件,通过从文件中读取数据表名称,循环导出所有表:如果过程中摄及到分表,可根据分表规则修改导出的sql语句和批处理代码,非常灵活。
database 为数据库实例名
@echo off & setlocal enabledelayedexpansionfor/f %%i in (tables.txt)do( set table=%%iecho"dump table -- !table! --"mysql -uroot -p12345678 database -e "SELECT * INTO OUTFILE 'F:/MySQL/Uploads/!table!.txt' FIELDS TERMINATED BY ',' FROM !table!")pause
Linux平台导入数据:
#!/bin/bashwhile read linedo mysql -uroot -p12345678 database -e "LOAD DATA INFILE '/var/lib/mysql-files/$line.txt' INTO TABLE $line FIELDS TERMINATED BY ','"done < tables.txt
问题记录(注意):
1.MYSQL导入数据出现The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
原因:MYSQL限制了导入与导出的目录权限
解决办法:
1.show variables like '%secure%';
查看 secure-file-priv 当前的值是什么,将导出文件目录设置成secure-file-priv的值
2.修改配置可修改mysql配置文件
查看是否有secure_file_priv =
这样一行内容,如果没有,则手动添加,
secure_file_priv = /home
表示限制为/home文件夹
secure_file_priv = 表示不限制目录,等号一定要有,否则mysql无法启动修改完配置文件后,重启mysql生效
操作三:复制文件迁移 a->b
于是我按照网上的说法,步骤如下:
一、把机器b的mysql停掉。
二、把机器a上要迁移的库的整个目录复制到机器b的mysql data目录下。
三、修改目录权限为700,修改文件权限为660,并修改他们的所属用户和所属组为mysql。
四、到机器b上,刚才建的那个数据库的目录下,把所有的(.ibd)文件删除掉。
五、把机器a上,对应数据库目录下所有的(.ibd)文件复制到机器b上,修改文件的权限。
六、再启动机器b的mysql。
操作四五步骤的原因如下:
show databases和show tables时,mysql其实是去目录下扫描,但执行select这些操作的时候,mysql优化器会去information_schema.TABLES 这个表里面获取信息。由于我们是直接复制文件过去,所以,这个表里面是没有信息的,所以就会提示表不存在。
参考文章:
1.http://www.codetc.com/article-322-1.html
2.http://blog.sina.com.cn/s/blog_59bba95d0102wspc.html