我正在通过命令行PHP脚本运行MySQL查询(使用mysqlnd驱动程序上的PDO准备好的查询).这是一个简单的查询,只有一个左连接,每行返回100行和7个小列.
当我在MySQL CLI中运行此查询时(在运行相关PHP脚本的同一台机器上),它需要0.10秒 - 即使抛出了SQL_NO_CACHE标志.
当我运行此查询时,通过PDO准备它需要超过9秒.这是执行()只 -这还不包括需要为获取呼叫的时间.
我的查询示例:
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;
Run Code Online (Sandbox Code Playgroud)
我不相信查询是错误的,考虑到我尝试过的每个原生MySQL客户端都在近乎即时运行它,但这里是解雇的EXPLAIN:
+----+-------------+-------+--------+-------------------------+------------+---------+-----------------------------------+------+-------------+
| 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)
Run Code Online (Sandbox Code Playgroud)
PDO在世界上做了什么,花了8.9秒?
编辑:正如评论中所述,我也写了一个mysql_query版本,它具有相同的糟糕性能.但是,删除部分WHERE子句会使其运行速度与MySQL客户端一样快.请继续阅读,了解令人难以置信的细节.
我有同样的问题.从cli和PHP启动时,相同的查询行为也不同.在cli中解释正确的索引用法,在PHP中没有任何内容.正如我所发现的,问题是类型转换,在我的例子中是datetime.之后我专门为比较值投了类型,例如.where datetime_column > cast('2014-01-12 12:30:01' as datetime)一切正常.
提供有关此问题的最新信息:
我还没有找到原因,但是事实证明,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;
Run Code Online (Sandbox Code Playgroud)
希望这对某人有帮助!