1. 程式人生 > >Mysql --學習:大量資料快速匯入匯出

Mysql --學習:大量資料快速匯入匯出

宣告:此文供學習使用,原文:https://blog.csdn.net/xiaobaismiley/article/details/41015783 

【實驗背景】

專案中需要對資料庫中一張表進行重新設計,主要是之前未分割槽,考慮到資料量大了以後要設計成分割槽表,同時要對資料庫中其他表做好備份恢復的工作。

【實驗環境】

  Mysql版本:mysql-5.6.19

  作業系統:Ubuntu 12.04

  記憶體:32G

  CPU:24核  Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz

  資料:單表1.6億條記錄,大小為22GB,非分割槽表,表中包含一個索引,並且存在int型自增主鍵

【匯出匯出工作準備】

  (1)匯出前關閉日誌,避免資料備份過程中頻繁記錄日誌

  (2)刪除主鍵,關閉自動增長。在該表中主鍵其實作用不大,自動增長是需要的(mysql中自動增長的一列一定要為key,所以設定為主鍵),等待資料轉移結束後重新設定回來

  (3)刪除表中索引。在插入資料時索引的存在會很大程度上影響速度,所以先關閉,轉移後重新建立

  (4)Mysql系統引數調優,如下:(具體含義後面給出)

innodb_data_file_path = ibdata1:1G:autoextend
innodb_file_per_table = 1
innodb_thread_concurrency 
= 20 innodb_flush_log_at_trx_commit = 1 innodb_log_file_size = 256M innodb_log_files_in_group = 3 innodb_max_dirty_pages_pct = 50 innodb_lock_wait_timeout = 120 key_buffer_size=400M innodb_buffer_pool_size=4G innodb_additional_mem_pool_size=20M innodb_log_buffer_size=20M query_cache_size=40M read_buffer_size
=4M read_rnd_buffer_size=8M tmp_table_size=16M max_allowed_packet = 32M

【操作方法及結果】

  (1)create table t2 as select * from t1

CREATE TABLE dn_location3 
PARTITION BY RANGE (UNIX_TIMESTAMP(UPLOADTIME))
( PARTITION p141109 VALUES LESS THAN (UNIX_TIMESTAMP('2014-11-09 00:00:00')),
PARTITION p141110 VALUES LESS THAN (UNIX_TIMESTAMP('2014-11-10 00:00:00')), 
PARTITION p141111 VALUES LESS THAN (UNIX_TIMESTAMP('2014-11-11 00:00:00')), 
PARTITION p141112 VALUES LESS THAN (UNIX_TIMESTAMP('2014-11-12 00:00:00')) 
) 
as select * from dn_location 
where uploadtime > '2014-08-04';
create table t2 as select * from dn_location2;

  as創建出來的t2表(新表)缺少t1表(源表)的索引資訊,只有表結構相同,沒有索引。
此方法效率較高,在前面的實驗環境下,42min內將一張表內4600W的資料轉到一張新的表中,在create新表時我添加了分割槽的操作,因此新表成功建立為分割槽表,這樣一步到位的既轉移了資料又建立了分割槽表。此方法平均速度:6570W條/h ,至於該方法其他需要注意的地方,暫時沒有去了解。

(2)使用MySQL的SELECT INTO OUTFILE 、Load data file

  LOAD DATA INFILE語句從一個文字檔案中以很高的速度讀入一個表中。當用戶一前一後地使用SELECT ... INTO OUTFILE 和LOAD DATA INFILE 將資料從一個數據庫寫到一個檔案中,然後再從檔案中將它讀入資料庫中時,兩個命令的欄位和行處理選項必須匹配。否則,LOAD DATA INFILE 將不能正確地解釋檔案內容。

假設使用者使用SELECT ... INTO OUTFILE 以逗號分隔欄位的方式將資料寫入到一個檔案中:

SELECT * INTO OUTFILE 'data.txt' FIELDS TERMINATED BY ',' FROM table2;

為了將由逗號分隔的檔案讀回時,正確的語句應該是:

LOAD DATA INFILE 'data.txt' INTO TABLE table2 FIELDS TERMINATED BY ',';

如果使用者試圖用下面所示的語句讀取檔案,它將不會工作,因為命令LOAD DATA INFILE 以定位符區分欄位值:

LOAD DATA INFILE 'data.txt' INTO TABLE table2 FIELDS TERMINATED BY '\t';

下面是我用來匯入匯出的命令:

1 select * into outfile 'ddd.txt' fields terminated by ',' from dn_location;
2 load data infile 'ddd.txt' into table dn_location2 FIELDS TERMINATED BY ',';

  通過該方法匯出的資料,是將各欄位(只有資料,不匯出表結構)資料存在一個檔案中,中間以逗號分隔,因為檔案中並不包含資料庫名或者表名,因此需要在匯入匯出的時候些明確。該方法在18分鐘內匯出1.6億條記錄,46min內匯入6472W條記錄,平均速度:8442W條/h。mysql官方文件也說明了,該方法比一次性插入一條資料效能快20倍。

【額外測試1】在新的表結構中增加主鍵,並增加某一列自增,檢視主鍵索引對插入效率的影響

  【結論】匯出效率沒有變化,匯入效率35min中匯入4600W條記錄,平均速度:7886W/h,考慮到測試次數很少,不能直接下結論,但至少明確該操作不會有明顯的效率下降。

【測試語句】

1 SELECT MOTOR_ID,LAT,LON,UPLOADTIME,RECEIVETIME,STATE_ID,SYS_STATE_ID,SPEED,DIR,A,GPRS,DISTANCE,WEEKDAY,GPSLOCATE INTO OUTFILE 'import2.txt' FROM dn_location3;
2 LOAD DATA INFILE 'import2.txt' INTO TABLE dn_location_withkey(MOTOR_ID,LAT,LON,UPLOADTIME,RECEIVETIME,STATE_ID,SYS_STATE_ID,SPEED,DIR,A,GPRS,DISTANCE,WEEKDAY,GPSLOCATE);

【額外測試2】在新建的表中對一個varchar型別欄位增加索引,再往裡匯入資料,檢視對插入效率的影響。

  【結論】匯入4600W條記錄耗時47min,效率確實有所降低,比僅有主鍵索引的測試多了12分鐘,從這裡看插入效率排序: 沒有任何索引 > 主鍵索引  >  主鍵索引+其他索引。

【額外測試3】在新建表中不加索引匯入資料,完全匯入後再建索引,檢視建立索引時間

  【結論】(1)表資料4600W,建立索引時間10min;表資料1.6億條,建立索引時間41min,由此可見建立索引的時間與表的資料量有直接關係,其他影響因素比較少;(2)從此處看先插入資料再建索引與先建索引再批量插入資料時間上差距不大,前者稍快一些,開發中應根據實際情況選擇。

(3)使用mysqldump ,source

mysqldump -u root -p -q -e -t webgps4 dn_location2 > dn_location2.sql
mysqldump -u root -p -q -e -t --single-transaction webgps4 dn_location2 > dn_location2.sql
source dn_location2.sql

  以上是匯入匯出資料的語句,該方法15分鐘匯出1.6億條記錄,匯出的檔案中平均7070條記錄拼成一個insert語句,通過source進行批量插入,匯入1.6億條資料耗時將近5小時。平均速度:3200W條/h。後來嘗試加上--single-transaction引數,結果影響不大。另外,若在匯出時增加-w引數,表示對匯出資料進行篩選,那麼匯入匯出的速度基本不變,篩選出的資料量越大,時間越慢而已。對於其中的引數這裡進行說明:
–quick,-q
  該選項在匯出大表時很有用,它強制 mysqldump 從伺服器查詢取得記錄直接輸出而不是取得所有記錄後將它們快取到記憶體中。

--extended-insert, -e
  使用具有多個VALUES列的INSERT語法。這樣使匯出檔案更小,並加速匯入時的速度。預設為開啟狀態,使用--skip-extended-insert取消選項。

--single-transaction

  該選項在匯出資料之前提交一個BEGIN SQL語句,BEGIN 不會阻塞任何應用程式且能保證匯出時資料庫的一致性狀態。它只適用於多版本儲存引擎,僅InnoDB。本選項和--lock-tables 選項是互斥的,因為LOCK TABLES 會使任何掛起的事務隱含提交。要想匯出大表的話,應結合使用--quick 選項。在本例子中沒有起到加快速度的作用
  mysqldump -uroot -p --host=localhost --all-databases --single-transaction

-t 僅匯出表資料,不匯出表結構

 

更多的mysqldump 引數說明請參考:http://blog.chinaunix.net/uid-26805356-id-4138986.html      

更多的mysql 引數調優說明參考:http://blog.csdn.net/yang1982_0907/article/details/20123055

                                                     http://blog.csdn.net/nightelve/article/details/17393631

extended-insert對mysqldump及匯入效能的影響  http://blog.csdn.net/hw_libo/article/details/39583247

 

參考資料:

http://www.tuicool.com/articles/6jEBJ3            mysql load data infile的使用 和 SELECT into outfile備份資料庫資料

http://kevin850115.iteye.com/blog/578142       Load Data使用方法

http://www.jb51.net/article/47525.htm               mysql幾種匯入匯出方法介紹