2012-09-27 166 views
3

我想導入一個csv文件到一個MySQL表中,我目前有一個腳本,一行一行地運行,因爲我需要散列一個ID結合另一個ID以及格式化日期爲mysql格式。導入大的CSV文件到MySQL

csv文件具有比我當前導入的列更多的列。只導入所有列是否更容易?

我正在閱讀關於LOAD DATA INFILE(http://dev.mysql.com/doc/refman/5.1/en/load-data.html),但我想知道如何使用它並散列ID並在不逐行執行的情況下格式化日期。我當前的腳本太長,導致運行時出現網站性能問題。

以下是我有:

$url = 'http://www.example.com/directory/file.csv'; 
if (($handle = fopen($url, "r")) !== FALSE) 
{ 
fgetcsv($handle, 1000, ","); 
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
{ 
    $EvID = $data[0]; 
    $Ev = $data[1]; 
    $PerID = $data[2]; 
    $Per = $data[3]; 
    $VName = $data[4]; 
    $VID = $data[5]; 
    $VSA = $data[6]; 
    $DateTime = $data[7]; 
    $PCatID = $data[8]; 
    $PCat = $data[9]; 
    $CCatID = $data[10]; 
    $CCat = $data[11]; 
    $GCatID = $data[12]; 
    $GCat = $data[13]; 
    $City = $data[14]; 
    $State = $data[15]; 
    $StateID = $data[16]; 
    $Country = $data[17]; 
    $CountryID = $data[18]; 
    $Zip = $data[19]; 
    $TYN = $data[20]; 
    $IMAGEURL = $data[21]; 
    $URLLink = $data[22]; 

     $data[7] = strtotime($data[7]); 
     $data[7] = date("Y-m-d H:i:s",$data[7]); 

    if((($PCatID == '2') && (($CountryID == '217') or ($CountryID == '38'))) || (($GCatID == '16') or ($GCatID == '19') or ($GCatID == '30') or ($GCatID == '32'))) 
    { 
      if(!mysql_query("INSERT IGNORE INTO TNDB_CSV2 
       (id, EvID, Event, PerID, Per, VName, 
        VID, VSA, DateTime, PCatID, PCat,     
       CCatID, CCat, GCatID, GCat, City, 
        State, StateID, Country, CountryID, Zip, 
       TYN, IMAGEURL) VALUES 
       ('".md5($EventID.$PerformerID)."','".addslashes($data[0])."','".addslashes($data[1])."','".addslashes($data[2])."','".addslashes($data[3])."','".addslashes($data[4])."', 
        '".addslashes($data[5])."','".addslashes($data[6])."','".addslashes($data[7])."','".addslashes($data[8])."','".addslashes($data[9])."', 
       '".addslashes($data[10])."','".addslashes($data[11])."','".addslashes($data[12])."','".addslashes($data[13])."','".addslashes($data[14])."', 
        '".addslashes($data[15])."','".addslashes($data[16])."','".addslashes($data[17])."','".addslashes($data[18])."','".addslashes($data[19])."', 
       '".addslashes($data[20])."','".addslashes($data[21])."')")) 
      {      
       exit("<br>" . mysql_error()); 
      } 
    } 
} 
fclose($handle); 
} 

任何幫助總是不勝感激。提前致謝。

回答

5

請先嚐試優化您的腳本。首先,在導入時不要運行單個查詢,除非你沒有別的選擇,網絡開銷可能是一個殺手。

試着這麼做(顯然未經測試,並在SO文本編碼,檢查括號匹配ECT):

$url = 'http://www.example.com/directory/file.csv'; 
if (($handle = fopen($url, "r")) !== FALSE) 
{ 
fgetcsv($handle, 1000, ","); 

$imports = array(); 

while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
{ 
    $EvID = $data[0]; 
    $Ev = $data[1]; 
    $PerID = $data[2]; 
    $Per = $data[3]; 
    $VName = $data[4]; 
    $VID = $data[5]; 
    $VSA = $data[6]; 
    $DateTime = $data[7]; 
    $PCatID = $data[8]; 
    $PCat = $data[9]; 
    $CCatID = $data[10]; 
    $CCat = $data[11]; 
    $GCatID = $data[12]; 
    $GCat = $data[13]; 
    $City = $data[14]; 
    $State = $data[15]; 
    $StateID = $data[16]; 
    $Country = $data[17]; 
    $CountryID = $data[18]; 
    $Zip = $data[19]; 
    $TYN = $data[20]; 
    $IMAGEURL = $data[21]; 
    $URLLink = $data[22]; 

     $data[7] = strtotime($data[7]); 
     $data[7] = date("Y-m-d H:i:s",$data[7]); 

    if((($PCatID == '2') && (($CountryID == '217') or ($CountryID == '38'))) || (($GCatID == '16') or ($GCatID == '19') or ($GCatID == '30') or ($GCatID == '32'))) 
    { 

    $imports[] = "('".md5($EventID.$PerformerID)."','".addslashes($data[0])."','".addslashes($data[1])."','".addslashes($data[2])."','".addslashes($data[3])."','".addslashes($data[4])."', 
        '".addslashes($data[5])."','".addslashes($data[6])."','".addslashes($data[7])."','".addslashes($data[8])."','".addslashes($data[9])."', 
       '".addslashes($data[10])."','".addslashes($data[11])."','".addslashes($data[12])."','".addslashes($data[13])."','".addslashes($data[14])."', 
        '".addslashes($data[15])."','".addslashes($data[16])."','".addslashes($data[17])."','".addslashes($data[18])."','".addslashes($data[19])."', 
       '".addslashes($data[20])."','".addslashes($data[21])."')"; 



    } 
} 

$importarrays = array_chunk($imports, 100); 
foreach($importarrays as $arr) { 

if(!mysql_query("INSERT IGNORE INTO TNDB_CSV2 
       (id, EvID, Event, PerID, Per, VName, 
        VID, VSA, DateTime, PCatID, PCat,     
       CCatID, CCat, GCatID, GCat, City, 
        State, StateID, Country, CountryID, Zip, 
       TYN, IMAGEURL) VALUES ".implode(',', $arr)){ 

    die("error: ".mysql_error()); 

} 

} 

fclose($handle); 
} 

玩弄數目array_chunk,過大,可能會導致像查詢過於問題很長(是的,my.cnf中有一個可配置的限制),太小而且沒有必要的開銷。

您也可以放棄將$ data [x]賦值給變量的使用,因爲在給定腳本有多小的情況下會浪費它,只需在查詢e.c.t中直接使用$ data [x]即可。 (不會大幅改善,但取決於您的進口尺寸,它可以節省一點)。

接下來的事情將是使用低優先級的插入/更新,看看這個更多的信息上,讓你開始:How to give priority to certain queries?

後,所有這一切,你能想到的mysql的配置優化的,但是這是一個爲谷歌解釋真的是最好的設置是每個人都不同,其獨特的情況

編輯:我之前所做的另一件事是,如果你有很多的設置按鍵未所需進口,您可以暫時放棄這些密鑰,並在腳本完成後將其添加回去。這也可以產生很好的時間改進,但是當你在一個實時數據庫上工作時,如果你沿着這條路線前進,那麼就會有陷阱。

+0

感謝您的建議李,你認爲這會產生重大的不同? – NotJay

+0

它應該,測試它並查看(谷歌的PHP定時器腳本,所以你可以量化它,如果你喜歡,或檢查出microtime()在php.net上的評論,確保在那裏你可以複製和粘貼)。具有相同插入結構的批處理查詢是我在慢腳本上執行的第一件事。但是,實際節省時間取決於許多因素。 – Lee

+0

現在需要不到30秒而不是15分鐘以上。謝謝你的幫助! – NotJay

1

我用這個查詢

$sql = " 
     LOAD DATA LOCAL INFILE 'uploads/{$fileName}' 
     REPLACE INTO TABLE `order` 
     FIELDS 
      TERMINATED BY '\t' 
     LINES 
      TERMINATED BY '\r\n' 
     IGNORE 1 LINES 
     (product_id, `date`, quantity) 
     "; 

它的超快速

+0

但不幸的是沒有工作 – Jarla