邏輯備份
mysqldump
mysqldump備份工具最初由Igor Romanenko編寫完成,通常用來完成轉存(dump)數據庫的備份以及不同數據庫之間的移植,例如從低版本的MySQL數據庫升級到高版本的MySQL數據庫,或者從MySQL數據庫移植到Oracle和SQL Server等數據庫等。
mysqldump的語法如下:
mysqldump [arguments] > file_name
如果想要備份所有的數據庫,可以使用--all-databaes選項:
mysqldump --all -databases > dump.sql
如果想要備份指定的數據庫,可以使用--databases選項:
mysqldump --databases db1 db2 db3 > dump.sql
如果想要對test這個架構進行備份,可以使用如下語句:
mysqldump --single -transaction test > test_backup.sql
我們使用--single-transaction選項來保證備份的一致性,備份出的test_backup.sql是文本文件,通過命令cat就可以查看文件的內容:cat test_backup.sql
可以看到,備份出的文件內容就是表結構和數據,所有這些都是用SQL語句表示的。文件開始和結束處的注釋是用來設置MySQL數據庫的各項參數的,一般用來使還原工作能更有效和准確的進行。之后的部分先是CREATE TABLE語句,之后就是INSERT語句了。
mysqldump的參數選項很多,可以通過mysqldump -help命令來查看所有的參數,有些參數有縮寫,如--lock-tables的縮寫為-l,重點介紹一些比較重要的參數。
--single-transaction:在備份開始前,先執行START TRANSACTION命令,以此來獲得備份的一致性,當前該參數只對InnoDB存儲引擎有效。當啟用該參數並進行備份時,確保沒有其他任何的DDL語句執行,因為一致性讀並不能隔離DDL語句。
--lock-tables(-l):在備份中,依次鎖住每個架構下的所有表。一般用於MyISAM存儲引擎,備份時只能對數據庫進行讀取操作,不過備份依然可以保證一致性。對於InnoDB存儲引擎,不需要使用該參數,用--single-transaction即可,並且-lock-tables和-single-transaction是互斥(exclusive)的,不能同時使用。如果你的MySQL數據庫中既有MyISAM存儲引擎的表,又有InnoDB存儲引擎的表,那么這時你的選擇只有--lock-tables了。另外,前面說了,--lock-tables選項是依次對每個架構中的表上鎖的,因此只能保證每個架構下表備份的一致性,而不能保證所有架構下表的一致性。
--lock-all-tables(-x):在備份過程中,對所有架構中的所有表上鎖。這可以避免之前提及的--lock-tables參數不能同時鎖住所有表的問題。
--add-drop-database:在CREATE DATABASE前先運行DROP DATABASE。這個參數需要和-all-databases或者-databases選項一起使用。默認情況下,導出的文本文件中並不會有CREATE DATABASE,除非你指定了這個參數,因此可能會看到如下內容:
mysqldump --single -transaction --add -drop -database --databases test > test_backup.sql
cat test_backup.sql
--master-data[=value]:通過該參數產生的備份轉存文件主要用來建立一個slave replication。當value的值為1時,轉存文件中記錄CHANGE MASTER語句;當value的值為2時,CHANGE MASTER語句被寫成SQL注釋。默認情況下,value的值為空。
當value值為1時,在備份文件中會看到:
mysqldump --single -transaction --add -drop -database --master -data=1 --databases test>test_backup.sql
cat test_backup.sql
CHANGE MASTER TO MASTER_LOG_FILE='xen-server-bin.000006',MASTER_LOG_POS=8095;
當value為2時,在備份文件中會看到CHANGE MASTER語句被注釋了:
mysqldump --single -transaction --add -drop -database --master -data=1 --databases test>test_backup.sql
cat test_backup.sql
--Position to start replication or point-in-time recovery from
--master-data會自動忽略-lock-tables選項。如果沒有使用-single-transaction選項,則會自動使用-lock-all-tables選項。
--events(-E):備份事件調度器。
--routines(-R):備份存儲過程和函數。
--triggers:備份觸發器。
--hex-blob:將BINARY、VARBINARY、BLOG、BIT列類型備份為十六進制的格式。mysqldump導出的文件一般是文本文件,但是,如果導出的數據中有上述這些類型,文本文件模式下可能有些字符不可見,若添加-he-blob選項,結果會以十六進制的方式顯示,如:
mysqldump --single -transaction --add -drop -database --master -data=2 --no -autocommit --databases test3 > test3_backup.sql
cat test3_backup.sql
LOCK TABLES'a'WRITE;
set autocommit=0;
INSERT INTO'a'VALUES(0x61000000000000000000);
UNLOCK TABLES;
可以看到,這里用0x61000000000000000000(十六進制的格式)來導出數據。
--tab=path(-T path):產生TAB分割的數據文件。對於每張表,mysqldump創建一個包含CREATE TABLE語句的table_name.sql文件和包含數據的tbl_name.txt。可以使用--fields-terminated-by=……,--fields-enclosed-by=……,--fields-optionally-enclosed-by=……,--fields-escaped-by=……,--lines-terminated-by=……來改變默認的分割符、換行符等,如:
mysqldump --single -transaction --add -drop -database --tab="/usr/local/mysql/data/test" test
大多數DBA喜歡用SELECT……INTO OUTFILE的方式來導出一張表,但是通過mysqldump一樣可以完成工作,而且可以一次完成多張表的導出,並且保證導出數據的一致性。
--where='where_condition'(-w 'where_condition'):導出給定條件的數據。
例如,導出b架構下的表a,並且表a的數據大於2,如下所示。
mysqldump --single -transaction --where='b>2' test a > a.sql
SELECT……INTO OUTFILE
SELECT……INTO語句也是一種邏輯備份的方法,或者更准確地說是導出一張表中的數據。
SELECT……INTO的語法如下:
SELECT [column 1], [column 2]……
INTO
OUTFILE 'file_name'
[{FIELDS|COLUMNS}
[TERMINATED BY'string']
[[OPTIONALLY]ENCLOSED BY'char']
[ESCAPED BY'char']
]
[LINES
[STARTING BY'string']
[TERMINATED BY'string']
]
FROM TABLE WHERE……
字段[TERMINATED BY 'string']表示每個列的分隔符,
[[OPTIONALLY]ENCLOSED BY'char']表示對於字符串的包含符,
[ESCAPED BY'char']表示轉義符,
[STARTING BY'string']表示每行的開始符號,
TERMINATED BY'string'表示每行的結束符號。
如果沒有指定任何FIELDS和LINES的選項,默認使用以下的設置:
FIELDS TERMINATED BY '\t'
ENCLOSED BY ''
ESCAPED BY '\\'
LINES TERMINATED BY '\n'
STARTING BY ''
file_name表示導出的文件,但文件所在的路徑的權限必須是mysql:mysql,否則MySQL會報告沒有權限導出:
select * into outfile '/root/a.txt' from a;
ERROR 1(HY000):Can't create/write to file'/root/a.txt'(Errcode:13)
查看通過SELECT INTO導出的表a文件:
select * into outfile '/home/mysql/a.txt' from a;
quit
cat /home/mysql/a.txt
1 a
2 b
可以發現,默認導出的文件是以TAB進行列分割的,如果想要使用其他分割符,如“,”,則可以使用FIELDS TERMINATED BY'string'選項,如:
mysql test -e "select * into outfile '/home/mysql/a.txt' fields terminated by','from a";
cat /home/mysql/a.txt
1,a
2,b
在Windows平台下,因為其換行符是“\r\n”,因此在導出時可能需要指定LINES TERMINATED BY選項,如:
mysql test -e "select * into outfile '/home/mysql/a.txt' fields terminated by',' lines terminated by '\r\n' from a";
od -c a.txt
0000000 1,a\r\n 2,b\r\n 3
0000017
邏輯備份的恢復
mysqldump的恢復
mysqldump的恢復操作比較簡單,因為備份的文件就是導出的SQL語句,一般只需要執行這個文件就可以了,可以通過以下的方法:
mysql -uroot -p123456<test_backup.sql
如果在導出時包含了創建和刪除數據庫的SQL語句,則必須確保刪除架構時架構目錄下沒有其他與數據庫無關的文件,否則可能會出現以下的錯誤:
drop database test;
ERROR 1010(HY000):Error dropping database(can't rmdir'./test',errno:39)
因為邏輯備份的文件是由SQL語句組成的,所以也可以通過SOURCE命令來執行導出的邏輯備份文件,如下所示:
source /home/mysql/test_backup.sql;
Query OK,0 rows affected(0.00 sec)
……
Query OK,0 rows affected(0.00 sec)
通過mysqldump可以恢復數據庫,但是常發生的一個問題是mysqldump可以導出存儲過程、觸發器、事件、數據,但是卻不能導出視圖。因此,如果你的數據庫中還使用了視圖,那么在用mysqldump備份完數據庫后還需要導出視圖的定義,或者保存視圖定義的frm文件,並在恢復時進行導入,這樣才能保證mysqldump數據庫的完全恢復。
LOAD DATA INFILE
若是通過mysqldump --tab或SELECT INTO OUTFILE導出的數據需要恢復時,這時需要通過LOAD DATA INFILE命令來進行導入。
LOAD DATA INFILE的語法如下所示:
LOAD DATA [LOW_PRIORITY|CONCURRENT] [LOCAL] INFILE 'file_name'
[REPLACE|IGNORE]
INTO TABLE tbl_name
[CHARACTER SET charset_name]
[{FIELDS|COLUMNS}
[TERMINATED BY'string']
[[OPTIONALLY]ENCLOSED BY'char']
[ESCAPED BY'char']
]
[LINES
[STARTING BY'string']
[TERMINATED BY'string']
]
[IGNORE number LINES]
[(col_name_or_user_var,……)]
[SET col_name=expr,……]
要對服務器文件使用LOAD DATA INFILE,必須擁有FILE權,其中導入格式的選項和之前介紹的SELECT INTO OUTFILE命令完全一樣。IGNORE number LINES選項可以忽略導入的前幾行。
下面來看一個用LOAD DATA INFILE命令導入文件的示例,並忽略第一行的導入:
load data infile '/home/mysql/a.txt' into table a;
為了加快InnoDB存儲引擎的導入,你可能希望導入過程忽略對外鍵的檢查,因此可以使用如下方式。
set @@foreign_key_checks=0;
load data infile '/home/mysql/a.txt' into table a;
set @@foreign_key_checks=1;
可以針對指定的列進行導入,如將數據導入列a、b,而c列等於a、b列之和:
create table b(a int,b int,c int,primary key(a))engine=innodb;
load data infile '/home/mysql/a.txt' into table b fields terminated by ',' (a,b) set c=a+b;
LOAD DATA INFILE命令可以用來導入數據,但同時可以完成對Linux操作系統的監控。如果需要監控CPU的使用情況,可以通過加載/proc/stat來完成。
首先我們需要建立一張監控CPU的表cpu_stat,其結構如下所示:
CREATE TABLE IF NOT EXISTS DBA.cpu_stat(
id bigint auto_increment primary key,
value char(25) NOT NULL,
user bigint,
nice bigint,
system bigint,
idle bigint,
iowait bigint,
irq bigint,
softirq bigint,
steal bigint,
guest bigint,
other bigint,
time datetime
);
接着可以通過用LOAD DATA INFILE命令來加載/proc/stat文件,但需要對其中一些數值進行轉化,命令如下所示:
LOAD DATA INFILE '/proc/stat'
IGNORE INTO TABLE DBA.cpu_stat
FIELDS TERMINATED BY''
(@value,@val1,@val2,@val3,@val4,@val5,@val6,@val7,@val8,@val9,@val10)
SET
value=@value,
user=IF(@value NOT LIKE 'cpu%', NULL,IF(@value!='cpu',IFNULL(@val1,0),IFNULL(@val2,0))),
nice=IF(@value NOT LIKE 'cpu%',NULL,IF(@value!='cpu',IFNULL(@val2,0),IFNULL(@val3,0))),
system=IF(@value NOT LIKE 'cpu%',NULL,IF(@value!='cpu',IFNULL(@val3,0),IFNULL(@val4,0))),
idle=IF(@value NOT LIKE 'cpu%',NULL,IF(@value!='cpu',IFNULL(@val4,0),IFNULL(@val5,0))),
iowait=IF(@value NOT LIKE 'cpu%',NULL,IF(@value!='cpu',IFNULL(@val5,0),IFNULL(@val6,0))),
irq=IF(@value NOT LIKE 'cpu%',NULL,IF(@value!='cpu',IFNULL(@val6,0),IFNULL(@val7,0))),
softirq=IF(@value NOT LIKE 'cpu%',NULL,IF(@value!='cpu',IFNULL(@val7,0),IFNULL(@val8,0))),
steal=IF(@value NOT LIKE 'cpu%',NULL,IF(@value!='cpu',IFNULL(@val8,0),IFNULL(@val9,0))),
guest=IF(@value NOT LIKE 'cpu%',NULL,IF(@value!='cpu',IFNULL(@val9,0),IFNULL(@val10,0))),
other=IF(@value like 'cpu%',user+nice+system+idle+iowait+irq+softirq+steal+guest,@val1),
time=now();
接着查看表cpu_stat,可以看到類似如下的內容:
select * from cpu_stat\G
***************************1.row***************************
id:1
value:cpu
user:2632896
nice:67761
system:688488
idle:4136329105
iowait:1468238
irq:0
softirq:106303
steal:148300
guest:0
other:4141441091
time:2010-09-10 12:01:04
***************************14.row***************************
id:14
value:procs_running
user:NULL
nice:NULL
system:NULL
idle:NULL
iowait:NULL
irq:NULL
softirq:NULL
steal:NULL
guest:NULL
other:1
time:2010-09-10 12:01:04
***************************15.row***************************
id:15
value:procs_blocked
user:NULL
nice:NULL
system:NULL
idle:NULL
iowait:NULL
irq:NULL
softirq:NULL
steal:NULL
guest:NULL
other:0
time:2010-09-10 12:01:04
15 rows in set(0.00 sec)
接着可以設置一個定時器來讓MySQL數據庫自動地運行上述LOAD DATA INFILE語句,這樣就會有每個時間點的CPU信息被記錄到表cpu_stat。
執行下述語句就可以得到每個時間點上CPU的使用情況:
select
100*((new.user-old.user)/(new.other-old.other))user,
100*((new.nice-old.nice)/(new.other-old.other))nice,
100*((new.system-old.system)/(new.other-old.other))system,
100*((new.idle-old.idle)/(new.other-old.other))idle,
100*((new.iowait-old.iowait)/(new.other-old.other))iowait,
100*((new.irq-old.irq)/(new.other-old.other))irq,
100*((new.softirq-old.softirq)/(new.other-old.other))softer,
100*((new.steal-old.steal)/(new.other-old.other))steal,
100*((new.guest-old.guest)/(new.other-old.other))guest,
new.time
from DBA.cpu_stat old,
DBA.cpu_stat new
where new.id-15=old.id
and old.value='cpu'
and new.value=old.value\G;
同樣,我們還可以對/proc/diskstat文件執行如上述所示的操作,這樣就又可以對磁盤進行監控操作了。
mysqlimport
mysqlimport是MySQL數據庫提供的一個命令行程序,從本質上來說,是LOAD DATA INFILE的命令接口,而且大多數的選項都和LOAD DATA INFILE語法相同。其語法格式如下:
mysqlimport [options] db_name textfile1[textfile2……]
與LOAD DATA INFILE不同的是,mysqlimport命令是可以導入多張表的,並且通過--user-thread參數來並發導入不同的文件。這里的並發是指並發導入多個文件,並不是指mysqlimport可以並發地導入一個文件,這是有區別的,並且並發地對同一張表進行導入,效果一般都不會比串行的方式好。
通過mysqlimport並發地導入兩張表。
mysqlimport --use -threads=2 test /home/mysql/t.txt /home/mysql/s.txt
如果在上述命令運行的過程中查看MySQL的數據庫線程列表,應該可以看到類似如下的內容:
show full processlist\G
***************************1.row***************************
Id:46
User:rep
Host:www.dao.com:1028
db:NULL
Command:Binlog Dump
Time:37651
State:Master has sent all binlog to slave;waiting for binlog to be updated
Info:NULL
***************************2.row***************************
Id:77
User:root
Host:localhost
db:test
Command:Query
Time:0
State:NULL
Info:show full processlist
***************************3.row***************************
Id:83
User:root
Host:localhost
db:test
Command:Query
Time:73
State:NULL
Info:LOAD DATA INFILE '/home/mysql/t.txt' INTO TABLE 't' IGNORE 0 LINES
***************************4.row***************************
Id:84
User:root
Host:localhost
db:test
Command:Query
Time:73
State:NULL
Info:LOAD DATA INFILE '/home/mysql/s.txt' INTO TABLE 's' IGNORE 0 LINES
4 rows in set(0.00 sec)
mysqlimport實際上是同時執行了2條LOAD DTA INFILE語句來完成並發導入操作。