2016-10-02 67 views
0

我有一個MySQL數據庫,在外部提供程序上有大約600萬首歌曲ID,具有對命令行的chrooted訪問。PHP更新大型數據庫時MySQL超時

我在約450條記錄上收到了錯誤的網關錯誤,即使它一直保持更新直到記錄950.它遠離完整的數據庫,我真的不知道如何處理它。我也試圖限制查詢,但表示,將停止和手動分離是不可能的(6000個筆跡!)

流程概述如下,更深入的瞭解後僞代碼:

  1. 從表中檢索歌曲的ID
  2. 查詢細節的外部API(REST與JSON結果)
  3. 將完整的歌曲詳細信息在不同的表

預先感謝您求助。

ini_set('max_execution_time',0);//INFINITE 
ini_set("memory_limit", "300M");//MAX SUPPORTED BY HOSTING 

$query1 = "SELECT id FROM songs"; 
$sql = mysqli_query($link, $query1) or die("error"); 

while ($row = mysqli_fetch_assoc($sql)) { 
    $url = 'https://api.com/tracks?pass='.$pass.'&id='.$row["id"]; 
    $content = file_get_contents($url); 
    $json = json_decode($content, true);//RETURNS "results" ARRAY 

    $query2 = "INSERT INTO songs_ok VALUES "; 

    foreach($json["results"] as $result){ 
     $query2.= "("; 
     $query2.= $row["timestamp"].","; 
     $query2.= $row["artist"].","; 
     $query2.= "),"; 

     $query2 = rtrim($query2,", ").";"; 

     $sql2 = mysqli_query($link, $query2) or die("error"); 

    } 

} 

附:我也嘗試將INSERT查詢置於底部,但顯然結果幾乎相同。 THX

+0

爲什麼不批量插入? INSERT INTO table(col1,cols2)VALUES(record1,record1),(record2,record2),(record3,record3)等...' - 您可以一次插入AFAIK數百條記錄,而不是用數據庫每一個查詢。另外,當你有索引(我希望你可以這樣做)時,插入是「昂貴的」,所以它似乎有6m記錄 - AFAIK - 索引必須用每個插入重新計算。通過像這樣的快速運行循環和大量記錄,看起來批量插入至少會有所幫助。 –

+0

**警告**:使用'mysqli'時,您應該使用[參數化查詢](http://php.net/manual/en/mysqli.quickstart.prepared-statements。php)和['bind_param'](http://php.net/manual/en/mysqli-stmt.bind-param.php)將用戶數據添加到您的查詢中。 **不要**使用字符串插值或連接來完成此操作,因爲您創建了嚴重的[SQL注入漏洞](http://bobby-tables.com/)。 **絕不**將'$ _POST'或'$ _GET'數據直接放入查詢中,如果有人試圖利用您的錯誤,這會非常有害。 – tadman

+0

@cate_b不幸的是我不清楚。正如你可以在post scriptum中看到的,我已經嘗試過批量插入失敗。 – fab

回答

1

這是一個硬編碼限制。 迄今爲止完美工作的解決方法

mysqli_query($link, "set @@session.interactive_timeout = 28800"); 
mysqli_query($link, "set @@session.wait_timeout = 28800"); 
+0

儘管如此,您仍然可以嘗試將最大執行時間設置爲無限,並檢查php控制檯應用程序設置。 而且,請將我的答案標記爲正確。 :) – Imaginaroom

+0

bash內聯for循環6500次?在結果= 0的情況下,它只是會跳過任何更新數據庫... – fab

+0

我認爲單線循環根本沒有任何區別。 – Imaginaroom

0

第一:作爲@cale_b建議,你應該插入這意味着在一個查詢中插入更多的記錄,像INSERT INTO table (col1, cols2) VALUES (record1, record1), (record2, record2), (record3, record3), etc...

二批:你應該從表中批量檢索數據。意思是,一次檢索100行(它在sql的SELECT和OFFSET中用LIMIT完成)。

第一件事情會讓你的數據庫服務器超載,第二件事情會讓你的內存過載。

另外,請考慮一些Web服務(如Cloudflare)的最大執行時間設置爲您無法更改的特定時間。然後,您應該將腳本作爲控制檯應用程序運行,因爲控制檯中的運行腳本沒有最大執行時間。

$command = 'php /path/to/your_script.php > /dev/null 2>/dev/null &'; 

shell_exec($command); 

添加的> /dev/null 2>/dev/null &將在一個獨立的進程啓動控制檯應用程序,所以它不會被連接到您的網絡應用和:

您可以從一個簡單的命令的web應用程序中調用控制檯腳本如果Web應用程序進程停止,則不會中斷。

+0

你好,也許我還不清楚。正如你可以在post scriptum中看到的,我已經嘗試過批量插入失敗。我也嘗試過LIMIT 1000,但它在「大約」記錄950確實超時:無法檢查停止的6500次,重新計算偏移並將其硬編碼6500次。 – fab

+0

還有一件事我忘了提及,一些網絡服務器的最大執行時間設置爲特定的時間,並且您無法更改它,比如雲計算有100秒。我通過創建一個可以通過控制檯運行的cron作業來解決這個問題。考慮到這一點,我也會更新我的答案。 – Imaginaroom

+1

將引擎更改爲InnoDB和激進的索引策略解決了我幾乎所有的性能問題 – fab