我正在通过命令行PHP脚本运行mysql查询(使用mysqlnd驱动程序上的PDO进行预查询)。这是一个简单的查询,只有一个左联接,返回100行,每行返回7小列。
当我在MySQL CLI中(在运行有问题的PHP脚本的同一台计算机上)运行此查询时,它花费了0.10秒-即使抛出了SQL_NO_CACHE标志。
当我运行此查询时,通过PDO进行准备需要9秒钟以上。这 仅 是execute()-不包括提取调用所需的时间。
我的查询示例:
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和CLI的解释是不同的。我不确定连接的任何方面是否会导致MySQL选择对索引使用不同的字段,因为据我所知,这些东西不应该相关。但是可惜,PHP的EXPLAIN显示未使用正确的索引,而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;
希望这对某人有帮助!