【问题标题】:Timing out while updating MySQL with PHP from a CSV从 CSV 使用 PHP 更新 MySQL 时超时
【发布时间】:2012-05-01 04:09:29
【问题描述】:

我需要想出一种方法来让大型任务更快地完成超时。

由于托管公司的限制,我对服务器的访问权限非常有限。

我有一个系统设置,其中一个 cron 访问一个 PHP 文件,该文件抓取一个包含某些产品数据的 csv。 csv 不包含产品将具有的所有字段。只有少数必要的。

我已经阅读了大量关于超时和处理 csv 的文章,目前(为了节省时间)我制作了一个表格(我们称之为 csv_data)来保存 csv 数据。我有一个截断 csv_data 表的脚本,然后从 csv 插入数据,因此每晚来自 csv 的最新记录集都在该表中(csv 文件每晚更新)。到目前为止,没有超时问题。任务只需要大约 4-5 秒。

当我必须筛选数据以更新产品表时,会发生超时。它现在运行的步骤是这样的

1. Get the sku from csv_data table (that holds thousands of records)
2. Select * from Products where products.sku = csv.sku (products table also holds thousands of records to loop through)
3. Get numrows.   
    If numrows<0{no record in products, so skip}. 
    If numrows>1{duplicate entries, don't change anything, but later on report the sku}
    If numrows==1{Update selected fields in the products table with csv data}
4. Go to the next record in csv_data all over again

(我发现概述这个过程比直接写代码更短更容易。) 我查看了 MySQl 视图和存储过程,但我不够熟练,不知道它是否会处理“if”语句部分。

我可以做些什么来加快速度以避免超时?

编辑:

我应该提到set_time_limit(0); 没有这样做。如果有帮助,服务器将使用 IIS7fastcgi 感谢您的帮助。

在使用 Jakob 和 Shawn 的建议后更新:

我做错了什么。速度肯定更快,而且csv sku在递增,

但是当我尝试实施肖恩的解决方案时;该查询给了我一个 PHP 警告:mysql_result() 期望参数 1 是资源,布尔错误。

你能帮我找出我做错了什么吗?

下面是这段代码:

$csvdata="SELECT * FROM csv_update";
    $csvdata_result=mysql_query($csvdata); 
    mysql_query($csvdata);
    $csvdata_num = mysql_num_rows($csvdata_result);
    $i=0;       
while($i<$csvdata_num){

$csv_code=@mysql_result($csvdata_result,$i,"skucode");

$datacheck=NULL;    
$datacheck=substr($csv_code,0,1);

if($datacheck>='0' && $datacheck<='9'){

$csv_price=@mysql_result($csvdata_result,$i,"price");
$csv_retail=@mysql_result($csvdata_result,$i,"retail");
$csv_stock=@mysql_result($csvdata_result,$i,"stock");
$csv_weight=@mysql_result($csvdata_result,$i,"weight");
$csv_manufacturer=@mysql_result($csvdata_result,$i,"manufacturer");
$csv_misc1=@mysql_result($csvdata_result,$i,"misc1");
$csv_misc2=@mysql_result($csvdata_result,$i,"misc2");
$csv_selectlist=@mysql_result($csvdata_result,$i,"selectlist");
$csv_level5=@mysql_result($csvdata_result,$i,"level5");
$csv_frontpage=@mysql_result($csvdata_result,$i,"frontpage");
$csv_level3=@mysql_result($csvdata_result,$i,"level3");
$csv_minquantity=@mysql_result($csvdata_result,$i,"minquantity");
$csv_quantity1=@mysql_result($csvdata_result,$i,"quantity1");
$csv_discount1=@mysql_result($csvdata_result,$i,"discount1");
$csv_quantity2=@mysql_result($csvdata_result,$i,"quantity2");
$csv_discount2=@mysql_result($csvdata_result,$i,"discount2");
$csv_quantity3=@mysql_result($csvdata_result,$i,"quantity3");
$csv_discount3=@mysql_result($csvdata_result,$i,"discount3");

    $count_check="SELECT COUNT(*) AS totalCount FROM products WHERE skucode = '$csv_code'";
    $count_result=mysql_query($count_check); 
    mysql_query($count_check);
    $totalCount=@mysql_result($count_result,0,'totalCount');
    $loopCount = ceil($totalCount / 25);
    for($j = 0; $j < $loopCount; $j++){

    $prod_check="SELECT skucode FROM products WHERE skucode = '$csv_code' LIMIT ($loopCount*25), 25;";
    $prodresult=mysql_query($prod_check); 
    mysql_query($prod_check);
    $prodnum =@mysql_num_rows($prodresult);
    $prod_id=@mysql_result($prodresult,0,"catalogid");


    if($prodnum<1){ 
    echo "NOT FOUND:$csv_code<br>";
    $count_sku_not_found=$count_sku_not_found+1;
    $list_sku_not_found=$list_sku_not_found." $csv_code";}

    if($prodnum>1){ 
    echo "DUPLICATE:$csv_ccode<br>";    
    $count_duplicate_skus=$count_duplicate_skus+1;
    $list_duplicate_skus=$list_duplicate_skus." $csv_code";}


if ($prodnum==1){
///This prevents an overwrite from happening if the csv file doesn't produce properly
    if ($csv_price!="" OR $csv_price!=NULL)
    {$sql_price='price="'.$csv_price.'"';}

    if ($csv_retail!="" OR $csv_retail!=NULL)
    {$sql_retail=',retail="'.$csv_retail.'"';}

    if ($csv_stock!="" OR $csv_stock!=NULL)
    {$sql_stock=',stock="'.$csv_stock.'"';}

    if ($csv_weight!="" OR $csv_weight!=NULL)
    {$sql_weight=',weight="'.$csv_weight.'"';}

    if ($csv_manufacturer!="" OR $csv_manufacturer!=NULL)
    {$sql_manufacturer=',manufacturer="'.$csv_manufacturer.'"';}

    if ($csv_misc1!="" OR $csv_misc1!=NULL)
    {$sql_misc1=',misc1="'.$csv_misc1.'"';}

    if ($csv_misc2!="" OR $csv_misc2!=NULL)
    {$sql_pother2=',pother2="'.$csv_misc2.'"';}

    if ($csv_selectlist!="" OR $csv_selectlist!=NULL)
    {$sql_selectlist=',selectlist="'.$csv_selectlist.'"';}

    if ($csv_level5!="" OR $csv_level5!=NULL)
    {$sql_level5=',level5="'.$csv_level5.'"';}

    if ($csv_frontpage!="" OR $csv_frontpage!=NULL)
    {$sql_frontpage=',frontpage="'.$csv_frontpage.'"';}



$import="UPDATE products SET $sql_price $sql_retail $sql_stock $sql_weight $sql_manufacturer $sql_misc1 $sql_misc2 $sql_selectlist $sql_level5 $sql_frontpage    $sql_in_stock WHERE skucode='$csv_code'";
 mysql_query($import) or die(mysql_error("error updating in products table"));


echo "Update ".$csv_code." successful ($i)<br>";

$count_success_update_skus=$count_success_update_skus+1;
$list_success_update_skus=$list_success_update_skus." $csv_code";



//empty out variables 
$sql_price='';
$sql_retail='';
$sql_stock='';
$sql_weight='';
$sql_manufacturer='';
$sql_misc1='';
$sql_misc2='';
$sql_selectlist='';
$sql_level5='';
$sql_frontpage='';
$sql_in_stock='';
$prodnum=0;

}
}
$i++;
}

【问题讨论】:

  • 显示您的代码,以便我可以帮助建议一个“惰性负载处理程序”
  • 不要在不需要的时候获取*(这也取决于每行有多少数据),如果你只需要知道numrows,只需获取一个id,或者单一值并以这种方式进行测试。
  • Jakub,谢谢 :) 我只抓住了 product.sku 字段,它把我的时间缩短到了大约 1.5 分钟,我已经超过了超时时间耶!!!!!!所以谢谢你,你肯定帮助改进了很多。我还将实现 Shawn 的想法,看看我是否能更快地得到它,因为虽然 1.5 分钟很好,但随着更多产品添加到 csv 中,我可以看到脚本需要更高的效率
  • 抱歉,该代码在格式和工作流程方面一团糟。但是,如果您谈到数千条记录,那应该不是问题。您在 SKU 列上有索引吗?

标签: php mysql csv cron timeout


【解决方案1】:

是在返回第一行之前超时还是在读取期间的行之间超时?一个好的做法是分块处理您的查询;首先进行计数以查看您正在为 SKU 处理多少条记录,循环通过较小的块(这些块的大小取决于您必须对每一行执行多少操作)。您更新后的工作流程看起来更像这样:

  1. 从 CSV 获取下一个 SKU
  2. 获取总数:SELECT COUNT(*) AS totalCount FROM products WHERE products.sku = csv.sku
  3. 确定块大小(本演示使用 25)
  4. loopCount = ceil(totalCount / 25)
  5. 使用这样的循环遍历所有结果:for($i = 0; $i &lt; loopCount; $i++)
  6. 在您的循环中,您应该运行如下查询:SELECT * FROM products WHERE products.sku = csv.sku LIMIT (loopCount*25), 25

你会想要为你的 SELECT 块使用一个固定的顺序;您的唯一 ID 可能是最好的。

【讨论】:

  • 行间超时。我已经使用只有 100 条记录的 csv 对其进行了测试,它工作正常(缓慢但很好)......我将尝试这种方法,看看是否能解决它:) 我会尽快更新。谢谢肖恩
  • 如果行之间超时,上述解决方案应该可以解决。我很想知道怎么去所以请回帖:)。此外,对于较小的文件,它可能会稍微慢一些,因为您正在执行多个请求,但您可以调整块大小以找到最佳性能/可靠性混合。享受吧!
  • 嗨,Shawn,我对 stackoverflow 还是比较陌生,所以如果我做得不对,请原谅我。我假设(通过评论框中的字符限制)我应该编辑您的答案以将我的回复放入。
  • Dustin,通常人们编辑自己的帖子并添加“解决方案:”部分,他们提供代码 sn-ps 等;这样,当其他人找到该帖子时,他们可以快速看到您是如何解决的。
  • 一切看起来都听起来不错,但是为什么在每次查询的地方都调用 mysql_query 函数两次?我没有全职开发 PHP,但这对我来说似乎很奇怪 :) 示例:$count_result=mysql_query($count_check); mysql_query($count_check);
【解决方案2】:

我认为你可以用 cron 解决这个问题。 http://en.wikipedia.org/wiki/Cron 。它从来没有超时。

【讨论】:

  • 我希望我能 cron。不幸的是,网络服务器提供的访问权限是极其无限的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-02
  • 2014-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多