2012-09-27 119 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