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
