2013-12-18 75 views
1

我需要運行一個每日cron作業,該作業遍歷一個6 MB CSV文件,以將每個〜10,000個條目插入MySQL表中。我寫的代碼掛起並在一段時間後產生一個超時。PHP將大型CSV文件導入到MySQL表中

if (($handle = fopen($localCSV, "r")) !== FALSE) { 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { 
     $dbdata = array(
      'SiteID' => $siteID, 
      'TimeStamp' => $data[0], 
      'ProductID' => $data[1], 
      'CoordX' => $data[2], 
      'CoordY' => $data[3] 
     ); 
     $row++; 
     $STH = $DBH->prepare("INSERT INTO temp_csv (SiteID,TimeStamp,ProductID,CoordX,CoordY) VALUES (:SiteID,:TimeStamp,:ProductID,:CoordX,:CoordY)"); 
     $STH->execute($dbdata); 
    } 
    fclose($handle); 
    echo $row." rows inserted."; 
} 

這本來是理想的使用mysql_*功能,而不是PDO,這樣我就可以爆的值到一個單獨的查詢(儘管巨大的),但不幸的是我需要遵守一些準則(PDO的使用僅限) 。

我搜索了,所以有非常類似的問題,但沒有人能解決我的問題。我嘗試的是以下內容:

1-冉LOAD DATA INFILELOAD DATA LOCAL INFILE查詢,但不斷收到「文件未找到」錯誤,雖然該文件肯定是有777權限。數據庫服務器和共享主機帳戶處於不同的環境中。我嘗試了csv文件的相對路徑和url路徑,但沒有運氣(在兩種情況下都找不到文件)。

2-我將csv文件拆分爲2個文件,並在每個文件上運行腳本,查看腳本掛起的閾值,但是在每個文件的情況下,它在表格中插入了兩次條目。

我無權訪問php.ini,因爲它是共享的託管帳戶(cloudsites),並且只能通過phpMyAdmin訪問MySQL

我還有什麼可以嘗試儘可能有效地完成這項工作?

任何幫助表示讚賞。

+1

我經常處理.csv - > mysql,我的一般策略是每個插入記錄多個記錄,例如,插入表值(一,二),(三,四),(五,六)等。 – Dave

+1

做一個批量插入會更好,而不是每行一個插入。 – user602525

+0

感謝@Dave,但是我怎樣才能在while循環中使用PDO呢?它會使用'mysql_ *',但我不能使用它。 –

回答

0

代碼看起來沒有錯。它掛起,因爲它需要一段時間才能執行。您應該使用phps set_time_limit來防止超時。

if (($handle = fopen($localCSV, "r")) !== FALSE) { 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { 
    set_time_limit(30) // choose a value that works for you 
    // ... the rest of your script 

更好,但會啓動一個後臺進程,其中CSV處理,那就需要某種鎖定的,所以它不會在多個實例並行運行。如果您將狀態寫入磁盤上的文件中,您可以輕鬆地將其呈現給用戶。 這同樣適用於cron腳本(如果您可以使用您的託管解決方案執行此操作)

PDO的使用對我來說看起來沒問題。我不會想到一次插入csv的所有行,但是您也可以使用PDO一次插入多行。爲多行創建語句和數據數組。它看起來是這樣的草圖(我沒有執行它,很可能會發生一些錯誤):

function insert_data($DBH, array $dbdata, array $values) { 
    $sql = "INSERT INTO temp_csv (SiteID,TimeStamp,ProductID,CoordX,CoordY) VALUES %1$s;"; 
    $STH = $DBH->prepare(sprintf($sql, join(', ', $values))); 
    $STH->execute($dbdata); 
} 

if (($handle = fopen($localCSV, "r")) !== FALSE) { 
    $dbdata = array(); 
    $values = array(); 
    $row = 0; 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { 
     if(!count($dbdata)) 
      $dbdata['SiteID'] = $siteID; 

     $dbdata['TimeStamp_'.$row] = $data[0]; 
     $dbdata['ProductID_'.$row] = $data[1]; 
     $dbdata['CoordX_'.$row] = $data[2]; 
     $dbdata['CoordY_'.$row] = $data[3]; 
     $values[] = sprintf('(:SiteID_%1$s,:TimeStamp_%1$s,:ProductID_%1$s,:CoordX_%1$s,:CoordY_%1$s)', $row); 
     $row++; 

     if($row % 10 === 0) { 
      set_time_limit(30); 
      insert_data($DBH, $dbdata, $values); 
      $values = array(); 
      $dbdata = array(); 
     } 
    } 
    // insert the rest 
    if(count($values)) 
     insert_data($DBH, $dbdata, $values); 
    fclose($handle); 
    echo $row." rows inserted."; 
} 

快捷至少閱讀在php.ini配置是phpinfo。看看PHP手冊,很多配置值可以在運行時從您的代碼中設置。

+0

爲什麼這是低調? – Lasse

+0

普通服務器可以插入至少1k記錄/秒。增加時間限制,仍然做錯事不是一個有效的解決方案。 – Skpd