關於MySQL的load data infile

最近經常使用mysql的load data infile導入數據。查閱了相關資料記錄下:

爲什麼load data infile 快

關於爲什麼Load data 會更快,查閱資料如下:

較短的SQL 語句比較長的SQL 語句要快,因爲它們涉及服務器方的分析較少,而且還因爲將它們通過網絡從客戶機發送到服務器更快。這些因素中有一些似乎微不足道(特別是最後一個因素),但如果要裝載大量的數據,即使是很小的因素也會產生很大的不同結果。我們可以利用上述的一般原理推導出幾個關於如何最快地裝載數據的實際結論:

  LOAD DATA(包括其所有形式)比INSERT 效率高,因爲其成批裝載行。索引刷新較少,並且服務器只需分析和解釋一條語句而不是幾條語句。

  LOAD DATA 比LOAD DATA LOCAL 效率更高。利用LOAD DATA,文件必須定位在服務器上,而且必須具有FILE 權限,但服務器可從磁盤直接讀取文件。利用LOAD DATA LOCAL,客戶機讀取文件並將其通過網絡發送給服務器,這樣做很慢。

另外就是insert 的話,每運行一句,就更新一次索引,load 的話,全部執行完了再更新一次索引 (參考自http://www.debugease.com/mysql/281384.html

究其根源主要是MySQL內部對於load 和 insert的處理機制不同.
Load的處理機制是:在執行load之前,會關掉索引,當load全部執行完成後,再重新創建索引.
Insert的處理機制是:每插入一條則更新一次數據庫,更新一次索引.
補充:另外,load與insert的不同還體現在load省去了sql語句解析,sql引擎處理,而是直接生成文件數據塊,所以會比Insert快很多.

摘自:http://www.itpub.net/thread-510339-1-1.html

即核心思想就是批量處理, insert也是可以提升的,處理方式就是進行批量insert

對於load infile只更新一次索引爲不確認,查看http://dev.mysql.com/doc/refman/5.1/zh/sql-syntax.html#load-data 爲執行該操作時爲了提升性能可以使用ALTER TABLE...DISABLE KEYS關閉然後再執行,執行後再ALTER TABLE...ENABLE KEYS再次創建索引,創建索引的速度會更快。 查看http://dev.mysql.com/doc/refman/5.1/en/load-data.html 

E文如下:
If you use LOAD DATA INFILE on an empty MyISAM table, all nonunique indexes are created in a separate batch (as for REPAIR TABLE). Normally, this makes LOAD DATA INFILE much faster when you have many indexes. In some extreme cases, you can create the indexes even faster by turning them off with ALTER TABLE ... DISABLE KEYS before loading the file into the table and using ALTER TABLE ... ENABLE KEYS to re-create the indexes after loading the file. See Section 8.3.2.1, “Speed of INSERT Statements”.

多個client做insert。使用insert delayed 也可以加速插入
在Mysql中只支持MyISAM,MEMORY,ARCHIVE,BLACKHOLE的引擎。

 insert delayed into tableA() values(A,B,C);
原理:Insert是客戶端發送sql到server,server做處理後將結果狀態返回給客戶端。使用Insert Delayed。是客戶端發送sql後,server把其加入隊列,馬上返回狀態給客戶端。客戶端可以繼續執行別的操作了。而server等到空閒後馬上插入這些隊列中的數據。如果是多個client來插入數據的時候,每個Client的應用程序可以馬上獲得返回狀態,進行之後的操作。而server端一旦空閒,就可以將整個隊列作爲一個block執行讀寫,這樣IO的操作耗時就會降低。 或者說就是異步處理。問題是可能產生執行失敗而無法知悉。(http://blog.sina.com.cn/s/blog_7e89c3f501012hzl.html)

注:這裏有個疑問時如果是索引值更新一次,怎麼解決load時的索引衝突問題呢

測試如下:

測試一爲對於數據庫已經存在的10000條記錄,執行load

load data infile '1.txt' ignore into table test_table fields terminated by ',';
Query OK, 0 rows affected (1.04 sec)
Records: 100000  Deleted: 0  Skipped: 100000  Warnings: 0

測試二爲對於數據庫不存在記錄,文件中有兩條,但是這兩條是重複的

 load data infile '1.txt' ignore into table test_table fields terminated by ',';
Query OK, 1 row affected (0.04 sec)
Records: 2  Deleted: 0  Skipped: 1  Warnings: 0

從測試結果看執行時還是會判斷重複的,是不是先將數據插入,然後再根據建立索引時再處理呢

測試三爲對於數據庫不存在記錄,文件中兩條,但是兩條id是重複的,但是內容不同,執行後查看數據庫的內容是前面這條還是後面這條。

load data infile '1.txt' ignore into table test_table fields terminated by ',';

Query OK, 1 row affected (0.05 sec)
Records: 2  Deleted: 0  Skipped: 1  Warnings: 0

即執行時跳過了一條。

文件內容爲:

1 100002,"hello 100001","test 100001"

2 100002,"hello 100002","test 100002"

select * from test_table where id = 100002;
+--------+----------------+---------------+
| id     | name           | attr          |
+--------+----------------+---------------+
| 100002 | "hello 100001" | "test 100001" |
+--------+----------------+---------------+

即爲第一條的值

測試四:

還是有重複記錄,但是執行load不忽略重複

      1 100003,"hello 100001","test 100001"
      2 100003,"hello 100002","test 100002"

load data infile '1.txt' into table test_table fields terminated by ',';
ERROR 1062 (23000): Duplicate entry '100003' for key 'index-1'

select * from test_table where id = 100003;
Empty set (0.00 sec)

即數據沒有導入


load data infile使用時注意點

以下部分轉載自:http://shanchao7932297.blog.163.com/blog/static/1363624201141135548221/

1)在客戶端也可以向遠程MySQL服務器執行 ‘load data‘ 命令,

      比如,客戶端IP: 192.168.204.132
                 服務器IP: 192.168.204.131
      可以在192.168.204.132上,
      執行命令: mysql -h 192.168.204.131 -utest -ptest test -e'load local data infile "/opt/xxxxx.txt" into table loadtest;'
   
      條件:
      如果使用源碼編譯的MySQL,在configure的時候,需要添加參數:--enable-local-infile     
      客戶端和服務器端都需要,否則不能使用local參數

2)load data infile 和 load local data infile 在   innodb和MyISAM 同步方面的區別
     對MyISAM引擎
          (1)對master服務器進行 ‘load’ 操作,
          (2)在master上所操作的load.txt文件,會同步傳輸到slave上,並在tmp_dir 目錄下生成 load.txt文件
               master服務器插入了多少,就傳給slave多少
          (3)當master上的load操作完成後,傳給slave的文件也結束時,
               即:在slave上生成完整的 load.txt文件
               此時,slave纔開始從 load.txt 讀取數據,並將數據插入到本地的表中

     對innodb引擎
          (1)主數據庫進行 ‘Load’ 操作
          (2)主數據庫操作完成後,纔開始向slave傳輸 load.txt文件,
               slave接受文件,並在 tmp_dir 目錄下生成 load.txt 文件
               接受並生成完整的load.txt 後,纔開始讀取該文件,並將數據插入到本地表中

    異常情況處理:
    1)對MyISAM引擎
         當數據庫執行load,此時如果中斷:
         Slave端將報錯,例如:
          ####################################################################
          Query partially completed on the master (error on master: 1053) and was aborted. 
          There is a chance that your master is inconsistent at this point. 
           If you are sure that your master is ok, 
           run this query manually on the slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; 
          START SLAVE; . Query: 'LOAD DATA INFILE '/tmp/SQL_LOAD-2-1-3.data' IGNORE INTO  TABLE `test_1` 
          FIELDS  TERMINATED BY ',' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`id`, `name`, `address`)'
          ###########################################################################################
          按照提示,在slave服務器上:
          (1) 使用提示的load命令,將主服務器傳輸過來的load文件,在從服務器上執行
          (2)讓從服務器跳過錯誤。set global sql_slave_skip_counter=1;
          (3)開啓同步
     2)對Innodb引擎
          由於innodb是事務型的,所以會把load文件的整個操作當作一個事務來處理,
          中途中斷load操作,會導致回滾。         
          與此相關的一些參數:
          max_binlog_cache_size----能夠使用的最大cache內存大小。
                                                    當執行多語句事務時,max_binlog_cache_size如果不夠大,
                                                    系統可能會報出“Multi-statement 
                                                     transaction required more than 'max_binlog_cache_size' bytes of storage”的錯誤。
           備註:以load data 來說,如果load的文件大小爲512M,在執行load 的過程中,
                     所有產生的binlog會先寫入binlog_cache_size,直到load data 的操作結束後,
                     最後,再由binlog_cache_size 寫入二進制日誌,如mysql-bin.0000008等。

                     所以此參數的大小必須大於所要load 的文件的大小,或者當前所要進行的事務操作的大小。

           max_binlog_size------------Binlog最大值,一般設置爲512M或1GB,但不能超過1GB。
                                                    該設置並不能嚴格控制Binlog的大小,尤其是Binlog遇到一根比較大事務時,
                                                    爲了保證事務的完整性,不可能做切換日誌的動作,只能將該事務的所有SQL都記錄進
                                                     當前日誌,直到事務結束
           備註:有時能看到,binlog生成的大小,超過了設定的1G。這就是因爲innodb某個事務的操作比較大,
                     不能做切換日誌操作,就全部寫入當前日誌,直到事務結束。


另外其還有個可能是導致死鎖:參見http://www.uml.org.cn/sjjm/201210302.asp 主要是存在自增id時
http://dev.mysql.com/doc/refman/5.1/zh/database-administration.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章