【问题标题】:increase performance of large csv file parsing in php-cli提高 php-cli 中大型 csv 文件解析的性能
【发布时间】:2015-05-25 02:24:54
【问题描述】:

晚上好,我有一个 400mb 的 csv 文件,我必须将它加载到 mysql 数据库中。 csv 文件是“不规则的”,因为它包含以下信息:

user|email|password\n
user|password|otherdata\n

我在 php-cli 中编写了一个脚本来逐行读取文件并获取我需要的信息:用户名和密码。 l '用户名永远是第一条记录。要知道'密码是什么我看字符串的长度。

我在五个小时前运行了脚本,但还没有完成数据库中所有数据的加载。

如何提高此脚本的性能?

<?php

$fileHandle = fopen("C:/Users/AT/Documents/Backup/forumusers.csv", "r");

$mysqlHandle = mysql_connect("localhost", "root", "");
mysql_select_db("testbackupboard");

while(!feof($fileHandle))
{
    $fileRow = fgets($fileHandle);
    $line2Record = explode("|", $fileRow);
    foreach ($line2Record as $rowRecord)
    {
        if (strlen($rowRecord) == 40)
        {
            $datatoMysql[0] = $rowRecord; // password hash
        }
    }
    $datatoMysql[1] = $line2Record[0]; // username

    $execQuery = mysql_query("INSERT INTO forumusers (username, hash) VALUES ('".mysql_real_escape_string(utf8_encode($datatoMysql[1]))."', '".mysql_real_escape_string(utf8_encode($datatoMysql[0]))."')");
    if($execQuery)
    {
        print"Record ".$rowRecord[1]." ".$rowRecord[0]." loaded into db\n";
    }
    else
    {
        die(mysql_error());
    }
}
fclose($fileHandle);

?>

【问题讨论】:

  • 规则 #1:如果可能,使用 MYSQL 的 LOAD DATA INFILE
  • 规则 #2:如果使用 PHP,则使用 PHP 内置的 fgetcsv() 函数而不是 fgets() 和 explode()
  • 规则 #3:如果使用 PHP,您不应该根据值的长度来寻找密码哈希,它应该是一个始终可识别的特定列......所以不要浪费精力将您的行减少到一个 2 条目数组,只需在 SQL 中使用 fgetcsv() 数组中的相关列
  • @Mark Ba​​ker:最好给出一个答案,而不是多个 cmets。在 AntonioT:有很多方法可以改善这一点。最快的方法之一是使用一个 INSERT 将多行插入到数据库中。您几乎可以通过一次插入的行数来加快速度。

标签: php mysql performance parsing csv


【解决方案1】:
  1. CREATE TABLE tmp 有 4 列:idAUTO_INCREMENT、usercol2col3。这不是决赛桌。
  2. LOAD DATA 用于所有行
  3. CREATE TABLE final (user, email, password, otherdata, PRIMARY KEY(user))
  4. 那么做
INSERT INTO final (user, email, password, otherdata)
    SELECT a.user, a.col2 AS email, a.col3 AS password,
           b.col3 AS otherdata
        FROM tmp AS a
        JOIN tmp AS b ON b.id = a.id+1
        WHERE (a.id % 2) = 1;

(警告:如果auto_increment_increment 不是 1,例如在基于 Galera 的集群上,这将不起作用。相反,您需要一个 @variable 来进行排序。)

【讨论】:

    【解决方案2】:

    fgetcsv() 怎么样?

    $row = 1;
    if (($handle = fopen("test.csv", "r")) !== FALSE) {
        while (($data = fgetcsv($handle, 1000, "|")) !== FALSE) {
            $num = count($data);
            echo "<p> $num fields in line $row: <br /></p>\n";
            $row++;
            for ($c=0; $c < $num; $c++) {
                echo $data[$c] . "<br />\n";
            }
        }
        fclose($handle);
    }
    

    【讨论】:

      猜你喜欢
      • 2014-01-15
      • 2017-01-28
      • 1970-01-01
      • 1970-01-01
      • 2011-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-09
      相关资源
      最近更新 更多