MariaDB/MySQL備份恢復系列:
備份和恢復(一):mysqldump工具用法詳述
備份和恢復(二):導入、導出表數據
備份和恢復(三):xtrabackup用法和原理詳述
1.導出、導入數據
load data infile和select into outfile語句是配套的。select into outfile語句是將檢索出來的數據按格式導出到文件中,數據遷移跨數據庫系統時,該選項很有用,因為它可以指定分隔符。load data infile是將帶有格式的數據文件導入到表中。
導出、導入數據時需要指定格式(如不指定,則使用默認)。格式涉及幾個方面:字段分隔符、行分隔符、引用符號、轉義符號。
還需注意一點,默認情況下(MySQL 5.6.34之后)這兩個語句無法執行成功,因為全局變量secure_file_priv的默認值為null,它表示禁用這兩種語句的導入導出。
所以應該將其設置為空(不指定任何值)或者指定一個目錄,將來該目錄中的所有文件都可以進行mysql file類的交互。當然,變量指定的目錄必須已經存在,且mysql系統用戶和組必須對該目錄有讀寫權限。
mkdir /data chown -R mysql.mysql /data
這個變量是全局靜態變量,只能在mysqld實例未啟動的時候才能修改。所以將其寫入配置文件。
[mysqld] secure-file-priv=/data # 或者 # secure-file-priv=
查看變量。
select @@global.secure_file_priv; +---------------------------+ | @@global.secure_file_priv | +---------------------------+ | /data/ | +---------------------------+
再看這兩個語句的語法:
SELECT ... INTO OUTFILE 'file_name' [CHARACTER SET charset_name] [export_options] LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name' [REPLACE | IGNORE] INTO TABLE tbl_name [CHARACTER SET charset_name] [export_options] [IGNORE number {LINES|ROWS}] [(col_name_or_user_var,...)] [SET col_name = expr,...] export_options: [{FIELDS | COLUMNS} [TERMINATED BY 'string'] [[OPTIONALLY] ENCLOSED BY 'char'] [ESCAPED BY 'char'] ] [LINES [STARTING BY 'string'] [TERMINATED BY 'string'] ]
其中'char'表示只能使用一個字符,'string'表示可以指定多個字符。
fields terminated by 'string'指定字段分隔符;enclosed by 'char'指定所有字段都使用char符號包圍,如果指定了optionally則只用在字符串和日期數據類型等字段上,默認未指定;escaped by 'char'指定轉義符。
lines starting by 'string'指定行開始符,如每行開始記錄前空一個制表符;lines terminated by 'string'為行分隔符。
要注意,在幾種情況下需要使用轉義符:數據中含有轉義符本身或者字段分隔符。當指定了字段引用符enclosed by時,如果數據中含有字段引用符,則也需要轉義,若未指定enclosed by,則默認不使用字段引用符,所以無需轉義。
以下為它們的默認值:
fileds terminated by '\t' enclosed by '' escaped by '\\' lines terminated by '\n' starting by ''
看上去語法還挺復雜的,使用示例來說明就很清晰易懂了。
給定如下表結構和數據。
create or replace table t(id int primary key,sex char(3),name char(20),ins_day date); insert into t values(1,'nan','longshuai1','2010-04-19'), (2,'nan','longshuai2','2011-04-19'), (3,'nv','xiaofang1','2012-04-19'), (4,'nv','xiaofang2','2013-04-19'), (5,'nv','xiaofang3','2014-04-19'), (6,'nv','xiaofang4','2015-04-19'), (7,'nv','tun\'er','2016-04-19'), (8,'nan','longshuai3','2017-04-19');
1.1 select into outfile導出數據
使用默認設置:
select * from t into outfile '/data/t_data.sql'; \! cat /data/t_data.sql 1 nan longshuai1 2010-04-19 2 nan longshuai2 2011-04-19 3 nv xiaofang1 2012-04-19 4 nv xiaofang2 2013-04-19 5 nv xiaofang3 2014-04-19 6 nv xiaofang4 2015-04-19 7 nv tun'er 2016-04-19 8 nan longshuai3 2017-04-19
指定字段分隔符",",使用單引號包圍各字段,每行前加上制表符。
select * from t into outfile '/data/t_data1.sql' fields terminated by ',' enclosed by '\'' lines starting by '\t' terminated by '\n'; \! cat /data/t_data1.sql '1','nan','longshuai1','2010-04-19' '2','nan','longshuai2','2011-04-19' '3','nv','xiaofang1','2012-04-19' '4','nv','xiaofang2','2013-04-19' '5','nv','xiaofang3','2014-04-19' '6','nv','xiaofang4','2015-04-19' '7','nv','tun\'er','2016-04-19' '8','nan','longshuai3','2017-04-19'
1.2 load data infile導入數據
要導入格式化后的純數據,可以使用load data infile,加載純數據的插入方式比直接執行insert插入至少快20多倍。但在內部,它們其實是等價行為,load data infile也會觸發insert相關觸發器。
其中可以使用local關鍵字表示從客戶端主機讀取文件,如果沒有指定local則表示從服務端主機讀取文件。
fields和lines的相關選項和select ... into outfile是一樣的,只不過load data infile多了幾個選項。其中ignore N lines|rows表示忽略前N行數據不導入,col_name_or_user_var表示按此處給定的字段和順序來導入數據,set col_name=expr表示對列進行一些表達式運算,如給某數值字段加5,給某字符串列尾部加上@qq.com字符等。
例如要加載如下文件到test.t表中。
cat /data/t_data.txt 1 nan longshuai1 2010-04-19 2 nan longshuai2 2011-04-19 3 nv xiaofang1 2012-04-19 4 nv xiaofang2 2013-04-19 5 nv xiaofang3 2014-04-19 6 nv xiaofang4 2015-04-19 7 nv tun'er 2016-04-19 8 nan longshuai3 2017-04-19
首先刪除表中數據,再導入。
truncate test. t; load data infile '/data/t_data.sql' into table test.t fields terminated by '\t';
將如下包含字段分隔符",",字段引用符"'",轉義符"\",行前綴"\t"的文件加載到test.t表中。
[root@xuexi ~]# cat /data/t_data1.sql '1','nan','longshuai1','2010-04-19' '2','nan','longshuai2','2011-04-19' '3','nv','xiaofang1','2012-04-19' '4','nv','xiaofang2','2013-04-19' '5','nv','xiaofang3','2014-04-19' '6','nv','xiaofang4','2015-04-19' '7','nv','tun\'er','2016-04-19' '8','nan','longshuai3','2017-04-19'
首先刪除表中數據,然后加載。
truncate test.t; load data infile '/data/t_data1.sql' into table test.t fields terminated by ',' enclosed by '\'' escaped by '\\' lines starting by '\t' terminated by '\n';
若要忽略前兩行,則:
truncate test.t; load data infile '/data/t_data1.sql' into table test.t fields terminated by ',' enclosed by '\'' escaped by '\\' lines starting by '\t' terminated by '\n' ignore 2 rows;
如果想在id列值加上5,則:
truncate test.t; load data infile '/data/t_data1.sql' into table test.t fields terminated by ',' enclosed by '\'' escaped by '\\' lines starting by '\t' terminated by '\n' set id=id+5;
如果想name列后加上"@qq.com"字符串,則:
truncate test.t; load data infile '/data/t_data1.sql' into table test.t fields terminated by ',' enclosed by '\'' escaped by '\\' lines starting by '\t' terminated by '\n' set name=concat(name,'@qq.com');
如果想同時執行上面兩個set,則:
truncate test.t; load data infile '/data/t_data1.sql' into table test.t fields terminated by ',' enclosed by '\'' escaped by '\\' lines starting by '\t' terminated by '\n' set name=concat(name,'@qq.com'), id=id+5;
1.3 mysqldump導出數據
和select into outfile功能類似的語句還有:此方法導出的數據中還包含了列名。
mysql -uroot -p123456 -e "select * from test.t">/tmp/t_data2.sql cat /tmp/t_data2.sql id sex name ins_day 1 nan longshuai1 2010-04-19 2 nan longshuai2 2011-04-19 3 nv xiaofang1 2012-04-19 4 nv xiaofang2 2013-04-19 5 nv xiaofang3 2014-04-19 6 nv xiaofang4 2015-04-19 7 nv tun'er 2016-04-19 8 nan longshuai3 2017-04-19
雖說select ... into outfile導出數據后可修改性和加載性非常強,但是畢竟沒有導出結構。要導出結構,可以使用mysqldump的"--tab"選項,它既會導出表的結構定義語句到同表名的.sql文件中,還會導出數據到同表名的.txt文件中。
mysqldump -uroot -p123456 --tab /data test t; ls -l /data/t.* -rw-r--r-- 1 root root 1408 Apr 19 14:46 /data/t.sql # test.t表定義語句 -rw-rw-rw- 1 mysql mysql 211 Apr 19 14:46 /data/t.txt # test.t表內數據
mysqldump的"--tab"選項同樣可以指定各種分隔符。如"--fields-terminated-by=...,--fields-enclosed-by=...,--fields-optionally-enclosed-by=...,--fields-escaped-by=..."。以下是指定字段分隔符為","。
mysqldump -uroot -p123456 --tab /data --fields-terminated-by=',' test t; cat /data/t.txt 1,nan,longshuai1,2010-04-19 2,nan,longshuai2,2011-04-19 3,nv,xiaofang1,2012-04-19 4,nv,xiaofang2,2013-04-19 5,nv,xiaofang3,2014-04-19 6,nv,xiaofang4,2015-04-19 7,nv,tun'er,2016-04-19 8,nan,longshuai3,2017-04-19
1.4 mysqlimport導入數據
mysqlimport和load data infile的本質是一樣的。mysqlimport在執行時會像服務端發送load data infile來加載數據,並且mysqlimport支持多進程並行導入多張表的數據。
mysqlimport的語法和load data infile基本一致。不同的是它在MySQL/MariaDB的外部執行,且可以一次性並行多線程導入多張表(並非並行導入一張表),所以能更快地導入所有數據。
mysqlimport [OPTIONS] database textfile...
注意:mysqlimport只能指定數據庫名來導入,所以導入的文件名必須和數據庫中的表名相對應(文件名后綴無所謂)。例如文件名為stu2.sql,而表名為student則無法導入,它會找stu2這個表。
例如,將以下格式的文件t.txt使用mysqlimport導入到test.t表中:
[root@xuexi ~]# cat /data/t.txt 1,nan,longshuai1,2010-04-19 2,nan,longshuai2,2011-04-19 3,nv,xiaofang1,2012-04-19 4,nv,xiaofang2,2013-04-19 5,nv,xiaofang3,2014-04-19 6,nv,xiaofang4,2015-04-19 7,nv,tun'er,2016-04-19 8,nan,longshuai3,2017-04-19 [root@xuexi ~]# mysqlimport -uroot -p123456 --fields-terminated-by=',' test '/data/t.txt'
使用"--use-threads"選項可以指定導入線程數。
例如,下面指定兩個線程,導入兩張表到數據庫test庫中的t1和t2表中。
mysqlimport -uroot -p123456 --use-threads=2 --fields-terminated-by=',' test '/data/t1.txt' '/data/t2.txt'