我遇到了一个 super 慢的 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)
好吧,认真的吗?我怎样才能在不到 0.1 秒的时间内在 MySQL 控制台中获得结果,而 PHP 却需要 2.5 秒来获取这 1000 个结果并将其放入一个简单的数组中?来吧,一个简单的 for 循环将 1000 个数字一个一个地放入一个数组中需要 0.001 秒......!!! 我在这里错过了什么?我可以使用什么作为替代品?我用谷歌搜索并搜索过,但找不到解决方案:(提前致谢!
编辑:fetchAll() 的持续时间不仅与返回结果的数量有关...而且与 $aArgs 的大小有关。不发送参数会使 fetchAll() 在 0.01 秒内返回,即使有 50K 个结果!为 execute() 调用提供 47K 个参数会使 fetchAll() 运行 120 秒。但这不是导致这种情况的大查询字符串的创建(顺便说一句,execute() 不是这样做的吗?),因为相同的 47K 参数,但 LIMIT 到 1K 结果只需要 2.5 秒...... 正如建议的那样,我已经验证 PDO 的 EXPLAIN 输出与使用 MySQL 控制台的输出相同。我也没有看到 MySQL 在努力工作,一直以来都是 Apache 进程(因此是 PHP)在占用 CPU。 另外:使用旧的 mysql_* 接口(interface),获取结果需要 0.03 秒。
背景信息
对于好奇的人:
- 它是本地 MySQL 5.5 数据库,因此不是远程服务器。
- PHP 版本:5.4.4。
- 这里的用例是系统中有许多过滤器(一个过滤器 = 一个数据库查询),以用户最喜欢的顺序运行,其中每个过滤器都从前一个过滤器中获取匹配条目的 ID运行,它应该返回剩余匹配条目的 ID(希望这是清楚的)。通过这种方式,过滤器最终用于选择与所有过滤器匹配的一小部分数据库条目。
- 有时我实际上有 47K 个结果要返回,然后延迟为 2.1 分钟,而查询时间不到 1 秒,这对我来说是 Not Acceptable 。
- 我明白,通过将多个过滤器组合到一个数据库查询中,我可以大大减少结果的数量。然而,过滤器是由用户选择的(因此组合不受限制),他们可以对不同的数据库表进行连接和检查,最后但并非最不重要的一点是,他们希望查看有关每个过滤器返回多少结果的统计信息。
最佳答案
您查询的 SQL 可以告诉我们一些信息。尝试运行 EXPLAIN SELECT ...
并查看查询计划是什么。检查索引是否被正确使用等。
然而,简单的执行调用和 fetchAll 调用之间的区别可能归结为以下几个因素:
- 底层驱动程序的性能 - 您使用的是
mysqlnd
驱动程序还是旧版本? - 结果集的大小 - 将所有数据加载到数组结构中将占用内存和时间
- 值得注意的是
PDOStatement->execute
无论如何只返回一个 bool 值
- 值得注意的是
首先,我会确保您已为 PHP 分配了足够的内存和 CPU,并检查 PHP 正在使用的 mysql 驱动程序。它应该是mysqlnd
。
关于php - PDOStatement::fetchAll() 太慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22811983/