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)

好吧,认真的?如何在不到 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 努力工作,一直在吃 CPU 的是 Apache 进程(因此是 PHP)。另外:使用较旧的 mysql_* 接口,获取结果需要 0.03 秒。

背景资料

对于好奇:

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

1 回答 1

0

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

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

  • 底层驱动程序的性能 - 您使用的是mysqlnd驱动程序还是旧版本?
  • 结果集的大小 - 将所有数据加载到数组结构中将占用内存和时间
    • 值得注意的是,PDOStatement->execute无论如何只返回一个布尔值

在第一个实例中,我会确保你有足够的内存和 CPU 分配给 PHP,并检查 PHP 正在使用的 mysql 驱动程序。应该是mysqlnd

于 2014-04-02T13:14:02.130 回答