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

标签 php mysql pdo

我正在通过命令行 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 客户端一样快。继续阅读,了解令人难以置信的细节。

最佳答案

对这个问题给出一个非常迟来的更新:

我还没有找到原因,但事实证明,PHP 中的 EXPLAIN 与 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;

希望这对某人有帮助!

关于PHP 运行查询的时间比 MySQL 客户端长 90 倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12336457/

相关文章:

mysql - 通过 strlen 从数据库中选择行

php - 如何根据条件向数组添加一些项目?

php - 如何在 Laravel 中的嵌套 2 级关系中按列排序?

php - Laravel 设置和获取 UTC 时间

php - 具有多行和删除的表

mysql - max_prepared_stmt_count错误,如何回收prepared statements?

php - 如何使用 PHPWord TemplateProcessor 更改 Word 文件的标题

php - 将来自多个文本字段的数据插入 MYSQL 数据库

php - 选择帖子、最后 3 条评论以及所有评论的计数

php - PDO 识别缺失的绑定(bind)变量