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

2022-08-31 01:11:46

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

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

当我通过 PDO 运行此查询时,它花费的时间超过 9 秒。这只是 execute() -- 不包括 fetch 调用所需的时间。

我的查询示例:

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 客户端一样快。请继续阅读,了解令人难以置信的细节。


答案 1

就此问题给出一个非常迟来的最新消息:

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

在这种情况下(令人困惑的)解决方案是使用索引提示。请参阅我示例中此修改后的查询中的“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

我遇到了同样的问题。从 cli 和 PHP 启动时,相同的查询的行为不同。在cli中解释正确的索引用法,在PHP中什么都没有。正如我所发现的,问题在于类型转换,在我的情况下是日期时间。在我专门为比较值(例如)强制转换类型之后。 一切都很好。where datetime_column > cast('2014-01-12 12:30:01' as datetime)


推荐