PHP运行查询的时间比MySQL客户端长90倍

时间:2012-09-09 04:11:33

标签: php mysql pdo

我正在通过命令行PHP脚本运行MySQL查询(在mysqlnd驱动程序上使用PDO准备好的查询)。这是一个简单的查询,只有一个左连接,每行返回100行和7个小列。

当我在MySQL CLI中运行此查询时(在运行相关PHP脚本的同一台机器上),它需要0.10秒 - 即使抛出了SQL_NO_CACHE标志。

当我运行此查询时,通过PDO准备它需要9秒以上。这是execute() only - 不包括获取调用所需的时间。

我的查询示例:

SELECT HEX(al.uuid) hexUUID, al.created_on,
    IFNULL(al.state, 'ON') actionType, pp.publishers_id publisher_id,
    pp.products_id product_id, al.action_id, al.last_updated
FROM ActionAPI.actionLists al
LEFT JOIN ActionAPI.publishers_products pp
    ON al.publisher_product_id = pp.id
WHERE (al.test IS NULL OR al.test = 0)
    AND (al.created_on >= :since OR al.last_updated >= :since)
ORDER BY created_on ASC
LIMIT :skip, 100;

我不相信查询是错误的,考虑到我尝试过的每个原生MySQL客户端都在附近立即运行它,但这里是探索的解释:

+----+-------------+-------+--------+-------------------------+------------+---------+-----------------------------------+------+-------------+
| id | select_type | table | type   | possible_keys           | key        | key_len | ref                               | rows | Extra       |
+----+-------------+-------+--------+-------------------------+------------+---------+-----------------------------------+------+-------------+
|  1 | SIMPLE      | al    | index  | created_on,last_updated | created_on | 8       | NULL                              |  100 | Using where |
|  1 | SIMPLE      | pp    | eq_ref | PRIMARY                 | PRIMARY    | 4       | ActionAPI.al.publisher_product_id |    1 |             |
+----+-------------+-------+--------+-------------------------+------------+---------+-----------------------------------+------+-------------+
2 rows in set (0.00 sec)

PDO正在做什么,这需要8.9秒?

编辑:正如评论中所述,我也写了一个mysql_query版本,它具有相同的糟糕性能。但是,删除部分WHERE子句会使其运行速度与MySQL客户端一样快。请继续阅读,了解令人难以置信的细节。

4 个答案:

答案 0 :(得分:6)

我遇到了同样的问题。从cli和PHP启动时,相同的查询行为不同。在cli中解释正确的索引用法,在PHP中没有任何内容。正如我所发现的,问题是类型转换,在我的例子中它是datetime。之后我专门为比较值投了类型,例如。 where datetime_column > cast('2014-01-12 12:30:01' as datetime)一切正常。

答案 1 :(得分:5)

对此问题提出非常迟到的更新:

我没有找到原因,但事实证明,EXPLAIN在PHP上与CLI不同。我不确定连接的任何方面是否会导致MySQL选择为索引使用不同的字段,因为据我所知,这些事情不应该相关;但是,PHP的EXPLAIN显示没有使用正确的索引,而CLI却没有使用。

这个(令人费解的)案例中的解决方案是使用index hinting。请参阅此示例中此修改后的查询中的“FROM”行:

SELECT HEX(al.uuid) hexUUID, al.created_on,
    IFNULL(al.state, 'ON') actionType, pp.publishers_id publisher_id,
    pp.products_id product_id, al.action_id, al.last_updated
FROM ActionAPI.actionLists al USE INDEX (created_on)
LEFT JOIN ActionAPI.publishers_products pp
    ON al.publisher_product_id = pp.id
WHERE (al.test IS NULL OR al.test = 0)
    AND (al.created_on >= :since OR al.last_updated >= :since)
ORDER BY created_on ASC
LIMIT :skip, 100;

希望这有助于某人!

答案 2 :(得分:2)

PDO使用资源来处理行结果。使用解释型语言(PHP),你将拥有比MySQL更长的处理脚本以返回结果的脚本。

注意:使用mysql_select_db()或mysqli_select_db()比PDO快得多。

要了解有关更快的PHP查询的详情,请参阅:PHP: What's the fastest way to query MySQL? Because PDO is painfully slow

答案 3 :(得分:0)

当您在命令行上连接时,很可能使用与PHP连接时使用的不同字符集。

当你要求它使用索引时,它会因为char集足够接近而不会导致问题(猜测?这取决于你设置的表和列)

尝试在那里放一些unicode charicters,它可能会开始返回不良结果。

确保char集在连接,表和列上匹配,以获得最佳结果。如果他们无法完成,那么连接是最重要的

UTF-8 vs Latin1 mysql, indexes not used on utf-8

有更多信息