【发布时间】:2014-04-02 12:46:40
【问题描述】:
我遇到了一个超级慢的 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 秒,在我的情况下是不可接受的。
- 我知道,通过将多个过滤器组合到一个数据库查询中,我可以大大减少结果数量。但是,过滤器是由用户选择的(因此组合不受限制),他们可以对不同的数据库表进行连接和检查,最后但并非最不重要的一点是,他们希望查看每个过滤器返回多少结果的统计信息。
【问题讨论】:
-
PHP 必须将数据从数据库的存储中传输到它自己的内存中并在那里进行后期处理。根据 PHP 和数据库之间的连接方式,这可能会导致一些延迟。无法说 2.5 秒在您的情况下是否合理,因为我们不知道设置的详细信息。
-
deceze 是对的,仍然可以说,通过适当的设置,PHP 使用的时间将与
mysql控制台客户端的时间相当。但请记住,控制台客户端不会执行 fetchAll.. 它将逐个遍历结果集。这样可以节省大量内存。你应该对 PHP 做同样的事情,否则结果无法比较 -
谢谢!关于“正确设置”的任何建议?它只是一个本地 MySQL (5.5.31) 数据库...删除我在 init 上设置的特殊 PDO 标志没有任何效果,所以我在那里没有做任何奇怪的事情。哦,使用 fetch() 循环并不能加快速度……
-
那么问题将是如何在您引用的文本之后直接修复“但是”之后的所有内容... -.- 问题仍然是为什么 PDO 完全能够在短时间内处理 50K 参数,完全能够在很短的时间内在 fetchAll() 中获取 50K 结果,但根本不处理两者的组合,而本机 mysql 客户端和 PHP 的 mysql_* 函数根本没有问题......
标签: php performance pdo fetchall