聲明:此文供學習使用,原文:https://blog.csdn.net/xiaobaismiley/article/details/41015783 html
項目中須要對數據庫中一張表進行從新設計,主要是以前未分區,考慮到數據量大了之後要設計成分區表,同時要對數據庫中其餘表作好備份恢復的工做。mysql
Mysql版本:mysql-5.6.19web
操做系統:Ubuntu 12.04sql
內存: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幾種導入導出方法介紹