好的,我会尽量保持这个简短,甜蜜和重点。
我们通过将MASSIVE CSV文件上传到基于PHP的CMS,对我们的系统进行大量的GeoIP更新。这件事通常有超过100k的IP地址信息记录。现在,简单地导入这些数据根本不是问题,但我们必须对当前的区域IP地址映射运行检查。
这意味着我们必须验证数据,比较和拆分重叠的IP地址等。并且必须对每条记录进行这些检查。
不仅如此,我还创建了一个字段映射解决方案,允许其他供应商以不同的格式实现其GeoIP更新。这是通过将规则应用于CSV更新中的IP记录来完成的。
例如,规则可能如下:
如果'countryName'=='澳大利亚'然后发送到'澳大利亚IP池'
可能需要运行多个规则,并且每个IP记录必须全部应用它们。例如,根据10条规则检查的100k记录将是100万次迭代;不好玩。
我们发现100条记录的2条规则最多需要10分钟才能处理完毕。我完全了解这里的瓶颈,即成功导入必须发生的剪切迭代量;只是没有充分意识到我们可能需要加快一些其他选择。
有人建议将文件拆分为服务器端的块。我不认为这是一个可行的解决方案,因为它为已经很复杂的系统增加了另一层复杂性。必须打开,解析和拆分该文件。然后脚本也必须遍历块。
所以,问题是,考虑到我刚刚写的内容,最好的方法是什么才能加快这个过程?不幸的是,升级服务器的硬件JUST对于这个工具不是一个选择,但它们是非常高端的盒子。
不像我想的那么短,但是。 HALPS? :(
答案 0 :(得分:12)
对数据库执行BULK IMPORT(SQL Server是我使用的)。 BULK IMPORT确实需要几秒钟,并且100,000条记录是花生数据库来处理业务规则。我经常在一张超过400万行的桌子上执行类似的数据运算,并且不需要你列出的10分钟。
编辑:我应该指出,是的,我不建议使用PHP。你正在处理原始数据,使用数据库..:P答案 1 :(得分:1)
这个简单的关键是尽可能多地保留内循环。
简单地说,你在内循环中所做的任何事情都是“100K次”完成的,所以什么都不做是最好的(但肯定不实际),所以尽可能少做是下一个最好的选择。
例如,如果您有内存,并且它对应用程序很实用,请将所有“输出”推迟到主处理之后。如果可行的话,缓存任何输入数据。这最适用于摘要数据或临时数据。
理想情况下,除了读取CSV文件外,在主要处理过程中尽量少做I / O.
PHP是否提供对Unix mmap工具的任何访问权限,这通常是读取文件的最快方式,特别是大文件。
另一个考虑因素是批量插入。例如,可以直接将INSERT语句构建为简单字符串,并以10,50或100行为单位将它们发送到服务器。大多数数据库对SQL语句的大小有一些硬性限制(如64K或其他东西),因此您需要牢记这一点。这将大大减少您到DB的往返。
如果您通过简单的增量创建主键,请执行大量(块1000,10000,无论如何)。这是你可以从内循环中删除的另一件事。
并且,当然,您应该为每一行立即处理所有规则,而不是为每个规则运行记录。
答案 2 :(得分:1)
100k记录不是一个大数字。单个线程的处理时间不是10分钟。无论你是使用PHP还是C,原始工作量都需要大约10分钟。如果你想要它更快,你需要一个比while循环更复杂的解决方案。
以下是我将如何处理它:
cat
。一个简单的版本可能是为每个10K记录块提供PHP fork进程,等待子进程,然后重新组合它们的输出。答案 3 :(得分:0)
您可以尝试的一件事是在命令行PHP下运行CSV导入。它通常可以提供更快的结果。
答案 4 :(得分:0)
如果您使用PHP来完成这项工作,请将解析切换到Python,因为在这方面它比PHP更快,这个交换应该将该过程加速75%甚至更多。
如果您使用MySQL,您也可以使用LOAD DATA INFILE运算符,我不确定您是否需要在将数据插入数据库之前检查数据。
答案 5 :(得分:0)
现在已经集中精力解决了这个问题。并且,是的,更好的解决方案是在任何时候只读取文件的一部分,解析它,进行验证,进行过滤,然后导出它,然后读取文件的下一部分。我同意这可能不是php的解决方案,虽然你可以在php中做到这一点。只要您具有搜索功能,就可以从文件中的特定位置开始阅读。你是对的它确实增加了更高级别的复杂性,但值得付出额外的努力。 你的数据是纯粹的,即正确分隔,字符串限定,没有破损线等,然后通过一切意味着批量上传到sql数据库。否则,您想知道错误发生的位置,时间和原因,并且能够处理它们。
答案 6 :(得分:0)
我正在使用类似的东西。
我正在使用的csv文件包含葡萄牙语数据(dd / mm / yyyy),我必须将其转换为mysql yyyy-mm-dd。葡萄牙货币:R $ 1.000,15,必须转换成mysql十进制1000,15。修剪可能的空格,最后添加.s
在插入之前有25个变量要处理。
如果我检查每个$ notafiscal值(选择进入表以查看是否存在并更新),php处理大约60k行。但如果我不检查它,php处理超过100万行。
服务器使用4GB的内存 - 脚本本地主机(内存为2GB),它在两种情况下处理半行。
mysqli_query($db,"SET AUTOCOMMIT=0");
mysqli_query($db, "BEGIN");
mysqli_query($db, "SET FOREIGN_KEY_CHECKS = 0");
fgets($handle); //ignore the header line of csv file
while (($data = fgetcsv($handle, 100000, ';')) !== FALSE):
//if $notafiscal lower than 1, ignore the record
$notafiscal = $data[0];
if ($notafiscal < 1):
continue;
else:
$serie = trim($data[1]);
$data_emissao = converteDataBR($data[2]);
$cond_pagamento = trim(addslashes($data[3]));
//...
$valor_total = trim(moeda($data[24]));
//check if the $notafiscal already exist, if so, update, else, insert into table
$query = "SELECT * FROM venda WHERE notafiscal = ". $notafiscal ;
$rs = mysqli_query($db, $query);
if (mysqli_num_rows($rs) > 0):
//UPDATE TABLE
else:
//INSERT INTO TABLE
endif;
endwhile;
mysqli_query($db,"COMMIT");
mysqli_query($db,"SET AUTOCOMMIT=1");
mysqli_query($db,"SET FOREIGN_KEY_CHECKS = 1");
mysqli_close($db);