使用大CSV更新数据库

时间:2012-08-24 07:02:53

标签: php sql csv phpmyadmin

我需要每天在MySql中更新~10,000项。我上传了一个CSV文件并尝试更新我的数据库数据。我正在分两个领域。我的问题是有效,但有一段时间我得到504网关超时,我的上传无法完成整个过程。

这是我的代码

if(is_uploaded_file($_FILES["filename"]["tmp_name"])){
        //      
        move_uploaded_file($_FILES["filename"]["tmp_name"], "".$_SERVER["DOCUMENT_ROOT"]."/upload/".$_FILES["filename"]["name"]);
    $file_path="".$_SERVER["DOCUMENT_ROOT"]."/upload/".$_FILES["filename"]["name"]."";

    $file=file_get_contents("".$file_path."");
    $file=iconv("windows-1251", "utf-8",$file);
    file_put_contents("".$file_path."",$file);

if(!setlocale(LC_ALL, 'ru_RU.utf8')) setlocale(LC_ALL, 'en_US.utf8'); if(setlocale(LC_ALL, 0) == 'C') die('       (ru_RU.utf8, en_US.utf8)');
    if (($handle_f = fopen($file_path, "r")) !== FALSE) { 
        //   csv
        while (($data_f = fgetcsv($handle_f,99999,";"))!== FALSE) {
            //   ean13 
            $sql="SELECT id_product FROM ps_product WHERE reference = '".$data_f[0]."'";
            $id_product = Db::getInstance()->getValue($sql,0);  

            //   ,    
            if ($id_product) {      
                $sql=mysql_query("UPDATE `ps_product` SET `quantity` ='".$data_f[1]."' WHERE `reference`='".$data_f[0]."'");
                echo "<p style='color:green'>Items<b>".$data_f[0]."</b> updated</p>";
            } else{
                echo "<p style='color:red  '>Items<b>".$data_f[0]."</b> not found</p>";
            }
        }
      echo "<b>Update is complited</b>";  

    }else{
        echo "Can`t open imported file";
    }
}else{
    echo '
    <h2>Quantity update:</h2>
    <form action="'.$_SERVER["PHP_SELF"].'" method="post" enctype="multipart/form-data">
              <input type="file" name="filename"><br>
              <input type="submit" value="Load"><br>
    </form>
    ';
}

现在我在excel中拆分了许多文件,每个失败约1000个并更新数据库。这需要一些时间。你能给我一个想法,或者我的代码中有错误吗?我认为使用ajax更新无济于事。

3 个答案:

答案 0 :(得分:0)

你有参考索引吗?如果不这样做,每次更新都需要很长时间。

另外,你有一些MAJOR SQL注入问题,并且mysql已经折旧,切换到mysqli。

答案 1 :(得分:0)

504 Bad Gateway Timeout是您的网关/代理服务器未从您的处理服务器获得timely response的时间。在这种情况下,即使处理服务器确实完成了所有更新,因为它没有向您的代理发送任何消息以让它知道处理仍在进行,代理会关闭连接。

在这种情况下,使用ajax进行更新并不是一个好主意。但是有一个名为ajax design pattern的{​​{1}}可以帮助您。基本思路是:

  1. 您正常致电处理页面以启动CSV更新
  2. 此外,您在页面中设置了一个javascript计时器,每隔X分钟对服务器页面进行一次ajax调用
  3. 服务器以简单的消息响应。甚至可以只是一个角色
  4. 您的客户端ajax可以忽略此消息,或打印它或其他任何
  5. X分钟后,同样的过程发生。
  6. 与此同时,您在第一步中启动的CSV处理仍在继续
  7. heartbeat pattern称为continuous message request and response。它有助于在您的服务器处理发生时保持heartbeat。一旦服务器处理结束并且您得到确认,您可以终止计时器并根据需要关闭连接。

    当然,在处理服务器端,您可以执行其他操作,例如connection aliveincrease timeout lenght等,以确保不会发生add database indexes

    但请注意,进程超时与网关超时不同。

答案 2 :(得分:0)

我需要将大量CSV加载到MySQL中,并且发现最佳解决方案是创建一个可以保存原始CSV数据的表。我使用与CSV相同的字段创建表,然后使用LOAD DATA进行批量导入,这很快,然后我可以使用SQL对数据执行必要的查询。

LOAD DATA LOCAL INFILE '{$filename}' 
INTO TABLE {$table_name} 
FIELDS TERMINATED BY '|' 
LINES TERMINATED BY '\n' 

在表中有CSV数据之后,您可以简单地以块(LIMIT和OFFSET)Psudeo代码运行查询,例如。

DEFINE("BLOCK_SIZE",100);

// Get the total rows in CSV table so when can divide into blocks
SELECT SQL_CALC_FOUND_ROWS  * 
FROM   my_csv_table
LIMIT  1;

$total_rows = SELECT FOUND_ROWS();

for($counter = 0; $counter < $total_rows; $counter += BLOCK_SIZE)
{

    SELECT * 
    FROM   my_csv_table
    LIMIT  BLOCK_SIZE
    OFFSET $loop_counter;

    foreach $row 
    {

        // UPDATE YOUR REAL TABLE IF MATCHED

    }

}