【发布时间】:2016-10-29 16:59:41
【问题描述】:
所以,我有这个包含 435,453 行数据的数据库。而且我有 271 家不同的公司需要从中获取特定信息,因此我目前正在尝试通过使用 MySQL 查询选择所有数据来聚合它,该查询在 1.28 秒内返回所有行,很好。
然后我想根据每个公司遍历它们并将它们写入文件(使用 fputcsv())。所以我首先使用 fopen() 271 次来创建文件,然后对于每个返回的行,我查看哪些公司将在该行中有数据并相应地写入文件。
现在,使用 memory_usage() 我可以看到在整个过程中内存使用量稳定在 6Mb。通过使用 microtime(),我正在计时我从数据库中读取的 while() 的每次迭代。
最终结果是每次迭代大约需要 0.00001 秒,因此对于数据库中的每一行,确定哪些公司应该拥有每一行并将其写入这些文件需要 0.00001 秒。
但是有些事情搞砸了,因为 100 分钟后,这个过程仍然没有完成,while() 每秒前进大约 100 行。如果我的数学是正确的,遍历 435,453 行,每行需要 0.00001 秒应该需要大约 4 秒。
这里是代码,或者是花了这么长时间的部分:
$q=mysql_query(bq($query)) or print mysql_error();
while ($r=mysql_fetch_assoc($q)){
$nr++;
$now = microtime(true);
if (($nr % 100) == 0 && $argv[1] == "debug"){
print "$nr: " . fsize(memory_get_usage()) . ", time: " . sprintf("%.5f", ($now - $savetime)) . "\n";
}
foreach ($xsps as $xsp => $sites){
if (!in_array($r["citynet"], $sites)) continue 1;
$data = format_fields($r, $xsp);
$values = array_values($data);
$keys = array_keys($data);
$linefeed = "\n";
# TXT
if ($nr == 1) fwrite($text[$xsp], join("\t", $keys) . $linefeed);
fputcsv($text[$xsp], $values, "\t");
# CSV
if ($nr == 1) fwrite($csv[$xsp], join(";", $keys) . $linefeed);
fputcsv($csv[$xsp], $values, ";");
}
$savetime = microtime(true);
}
每 100 行打印一次的输出如下所示:
12600: 6 Mb, time: 0.00000
12700: 6 Mb, time: 0.00000
12800: 6 Mb, time: 0.00000
12900: 6 Mb, time: 0.00001
13000: 6 Mb, time: 0.00000
13100: 6 Mb, time: 0.00000
13200: 6 Mb, time: 0.00000
那么,很明显 - 我做错了什么?数字说没有,怎么可能需要这么长时间?
编辑 所以,显然我的计算方式是错误的,所以我将其编辑为:
while ($r=mysql_fetch_assoc($q)){
$nr++;
$start = microtime(true);
if (($nr % 100) == 0 && $argv[1] == "debug"){
print "$nr: " . fsize(memory_get_usage()) . ", time: " . sprintf("%.5f", $processtime) . "\n";
}
...
$stop = microtime(true);
$processtime = ($stop - $start);
}
现在它报告每行需要 0.15 秒才能完成,这意味着整个过程需要 108 分钟。所以现在的实际问题是——为什么这么慢?是 fputcsv() 慢还是 PHP 慢?
【问题讨论】:
-
时间看起来不正确。在 foreach 循环之后,您存储时间,然后返回到 while 循环的开头并再次获取时间。
$now几乎在$savetime之后立即计算。我认为你应该在$nr % 100 == 0和$savetime应该在开始时计算$savetime,而$now时间需要在foreach之后,然后计算差异。 -
@Ctc 不,这是从命令行运行的
-
@sandman 我的错,没有真正正确地阅读它。让我再读一遍。
-
尝试将结果/行存储在临时变量中,并在循环结束时或偶尔($nr % 100 或 1000)将它们转储到文件中,然后查看执行时间如何变化。在大多数情况下,写操作是瓶颈。
-
请stop using
mysql_*functions。 These extensions 已在 PHP 7 中删除。了解PDO 和 MySQLi 的 prepared 语句并考虑使用 PDO,it's really pretty easy。