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幾種導入導出方法介紹




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM