PDOStatement::fetchAll() 速度太慢

4

我遇到了一个非常缓慢的PDOStatement :: fetchAll()问题,这让我感到很烦恼。我的查询时间不到0.1秒。在MySQL终端中,我的输出也在不到0.1秒的时间内显示在屏幕上。但是在PDOStatement上运行fetchAll()需要2.5秒。

// $_DB is my PDO class instance.
$tStart = microtime(true);
$q = $_DB->prepare('SELECT id FROM ... WHERE ... LIMIT 1000');
$q->execute($aArgs);
var_dump(round(microtime(true) - $tStart, 5));
$aIDsFiltered = $q->fetchAll(PDO::FETCH_COLUMN, 0);
var_dump(round(microtime(true) - $tStart, 5));exit;

这将输出:
float(0.0612)
float(2.58708)

好的,认真地说?我怎么可以在MySQL控制台中在不到0.1秒的时间内获得我的结果,但是PHP需要2.5秒才能获取那1000个结果并将其放入一个简单的数组中呢?来吧,一个简单的for循环逐个将1000个数字放入数组中只需要0.001秒... !!!

我错过了什么?我可以使用什么替代方案?我已经谷歌搜索了一遍,但是找不到解决方案:( 提前致谢!

编辑:fetchAll()的持续时间不仅与返回的结果数量有关...而且与$aArgs的大小有关。不发送参数使得fetchAll()在0.01秒内返回,即使有50K的结果!向execute()调用提供47K个参数使得fetchAll()需要120秒才能运行。但它不是创建大查询字符串导致这种情况(顺便问一下,execute()会做到这一点吗?),因为相同的47K参数,但是限制为1K个结果只需要2.5秒...

如建议所述,我已经验证了PDO与使用MySQL控制台的EXPLAIN输出是相同的。我也没有看到MySQL在努力工作,而是Apache进程(因此是PHP)在占用CPU。

另外:使用较旧的mysql_*接口,结果的提取只需要0.03秒。

背景信息

对于好奇心:

  • 这是一个本地MySQL 5.5数据库,因此不是远程服务器。
  • PHP版本:5.4.4。
  • 在这种情况下,系统中有一些过滤器(一个过滤器=一个数据库查询),按用户喜欢的顺序运行,在每个过滤器运行时都会传递前一个过滤器运行的匹配条目的ID,并且它应该返回剩余匹配条目的ID(希望这很清楚)。通过这种方式,过滤器用于最终选择与所有过滤器匹配的数据库条目的小子集。
  • 有时我确实有要返回47K个结果的情况,然后延迟为2.1分钟,而查询时间少于1秒,这在我的情况下是不可接受的。
  • 我知道我可以通过将几个过滤器合并为一个数据库查询来大大降低结果数。但是,过滤器由用户选择(因此无限组合),它们可以在不同的数据库表上进行联接和检查,并且最后但并非最不重要的是,他们希望看到每个过滤器返回多少结果的统计数据。

2
PHP需要将数据从数据库存储转移到自己的内存中,并在那里进行后处理。根据PHP和数据库之间的连接方式,这可能会产生一些延迟。由于我们不知道设置的详细信息,因此无法确定在您的情况下2.5秒是否合理。 - deceze
谢谢!有关“适当的设置”的建议吗?它只是一个本地MySQL(5.5.31)数据库...删除我在初始化时设置的特殊PDO标志没有任何效果,所以我在那里没有做任何奇怪的事情。 哦,使用fetch()循环并不能加快速度... - ifokkema
@DCoder:谢谢!猜猜看……旧的mysql_*接口在0.03秒内运行了fetch!所以肯定与PDO有关……但我注意到还有一些非常奇怪的事情,等我测试结果都出来后,稍后会更新我的问题。 - ifokkema
1
然后问题就是如何直接修复你引用的文本后面紧跟着的“但是”之后的所有内容... -.- 问题仍然是为什么PDO完全能够在很短的时间内处理50K个参数,在fetchAll()中完全能够获取50K个结果,但不能同时处理两者的组合,而本地mysql客户端和PHP的mysql_*函数则没有任何问题... - ifokkema
1
相关链接:https://dev59.com/g2855IYBdhLWcg3wbjrO - https://dev59.com/Zavka4cB1Zd3GeqPs274 - Paul Spiegel
显示剩余7条评论
1个回答

0

你的查询SQL可能会告诉我们一些信息。尝试运行一个EXPLAIN SELECT ...并查看查询计划是什么。检查索引是否被正确使用等。

然而,简单执行调用和fetchAll调用之间的区别可能归结于以下几个因素:

  • 底层驱动程序的性能-您是否正在使用mysqlnd驱动程序或旧版本?
  • 结果集的大小-将所有数据加载到数组结构中将需要内存和时间
    • 值得注意的是,PDOStatement->execute只返回布尔值

首先,我会确保您已经为PHP分配了足够的内存和CPU,并检查PHP正在使用的mysql驱动程序。它应该是mysqlnd


1
感谢您抽出时间回答!但是,查询不是问题。它在不到0.1秒的时间内完成(不仅在PHP中,在控制台中也是如此)。我切换到了mysqlnd驱动程序,但没有任何区别。大小如查询中所显示,为1000个结果(仅为数字ID)。在现实生活中,可能会返回47K个结果(当然,问题会变得更大)。 - ifokkema
1
为什么要将你的闲言碎语以答案的形式发布呢?在问题下面留评论完全可以满足他们的需求。 - Your Common Sense

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接