簡體   English   中英

優化大量的MySQL INSERT

[英]Optimize massive MySQL INSERTs

我有一個需要運行日常腳本的應用程序; 日常腳本包括下載具有1,000,000行的CSV文件,然后將這些行插入表格中。

我將應用程序托管在Dreamhost中。 我創建了一個while循環,該循環遍歷了CSV的所有行,並為每個循環執行INSERT查詢。 問題是我收到“ 500 Internal Server Error”。 即使我將其分成1000個文件(每個文件具有1000行),在同一循環中也不能插入40或5萬行以上。

有什么方法可以優化輸入? 我也在考慮使用專用服務器。 你怎么看?

謝謝!

佩德羅

大多數數據庫都有優化的大容量插入過程-MySQL的是LOAD DATA FILE語法

要加載CSV文件,請使用:

LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
  FIELDS TERMINATED BY ',' ENCLOSED BY '"'
  LINES TERMINATED BY '\r\n'
  IGNORE 1 LINES;

插入多個值,而不是這樣做

insert into table values(1,2);

insert into table values (1,2),(2,3),(4,5);

一次最多可容納適當數量的行。

或執行批量導入,這是加載數據的最有效方式,請參閱

http://dev.mysql.com/doc/refman/5.0/en/load-data.html

通常,我會說只使用LOAD DATA INFILE,但似乎您不能使用共享的托管環境。

我已經有好幾年沒有使用MySQL了,但是他們有一個很好的文檔,描述了如何加快批量插入的速度: http : //dev.mysql.com/doc/refman/5.0/en/insert-speed .html

可以從中得出一些想法:

  • 禁用/啟用插入周圍的鍵:

    ALTER TABLE tbl_name DISABLE KEYS; ALTER TABLE tbl_name啟用鍵;

  • 在您的插入語句中使用許多值。

    即:INSERT INTO表(col1,col2)值(val1,val2),(..,..),...

    如果我沒記錯的話,每個插入語句最多可以有4096個值。

  • 在開始之前,請運行FLUSH TABLES命令,以確保不存在任何可能影響插入性能的掛起磁盤寫操作。

我認為這將使事情變得更快。 我建議您使用LOCK TABLES,但是我認為禁用按鍵會引起爭議。

更新

閱讀此書后,我意識到,通過禁用密鑰,可以刪除對文件加載很重要的一致性檢查。 您可以通過以下方法解決此問題:

  • 確保您的表中沒有與正在加載的新數據“沖突”的數據(如果您是從頭開始的話,這里的TRUNCATE語句將很有用)。
  • 編寫腳本來清理您的輸入數據,以確保本地沒有重復。 無論如何,檢查重復項可能會花費大量的數據庫時間。
  • 如果這樣做,則ENABLE KEYS應該不會失敗。

轉到phpmyadmin並選擇要插入的表。

在“操作”選項卡下,然后在“表選項”選項/ section下,將存儲引擎從InnoDB更改為MyISAM。

我曾經遇到過類似的挑戰。 玩的很開心。

您可以創建cronjob腳本,該腳本應一個請求將x個記錄添加到數據庫中。 Cronjob腳本將檢查最后一次導入是否未添加所有需要的行(他需要另外X行)。

因此,您可以添加所需數量的行。

如果您擁有專用服務器,它將更加容易。 您只需對所有插入查詢運行循環。

當然,您可以嘗試將time_limit設置為0(如果在Dreamhost上運行)或使其更大。

您的PHP腳本很可能已終止,因為它超出了腳本時間限制。 由於您位於共享主機上,因此您很不走運。

如果您確實切換到專用服務器並且可以訪問外殼程序,則最好的方法是使用mysql命令行工具插入數據。

OMG Ponies的建議很好,但我也已將數據“手動”格式化為mysqldump使用的相同格式,然后以這種方式加載。 非常快。

您是否嘗試過交易? 只需將命令BEGIN發送到MySQL,完成所有插入操作,然后執行COMMIT 這樣可以大大加快速度,但是就像casablanca所說的那樣,您的腳本也可能會超時。

我自己之前曾遇到過這個問題,幾乎無法完全解決,但您需要做更多的工作才能使其表現最佳。

我發現在我的情況下,我無法接受一個大的INSERT語句,但是發現,如果像一次nos建議那樣一次將它分成大約10k個INSERTS組,它將很快完成工作。 需要注意的一件事是,當執行這樣的多個INSERT時,您很可能會達到PHP的超時限制,但是可以通過使用set_time_limit($ seconds)重置timout來避免這種情況,我發現在每次成功執行INSERT后都可以這樣做。

您必須謹慎執行此操作,因為您可能會因無限制的超時而陷入意外循環,為此,我建議您通過使用mysql_errno()檢查MySQL報告的錯誤來進行測試,以確保每個INSERT成功或mysql_error() 您還可以使用mysql_affected_rows()檢查受INSERT影響的行數來捕獲錯誤。 您可以在第一個錯誤發生后停止。

如果使用sqlloader會更好。 您將需要兩件事,第一件事是控制文件,該文件指定SQL Loader應該執行的操作,第二件事是要加載的csv文件。這是下面的鏈接,它可以為您提供幫助。 http://www.oracle-dba-online.com/sql_loader.htm

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM