我的MySQL查询有问题,我无法对其进行优化。
SELECT
p.id,
p.name,
p.sku,
p.type
FROM
xm_products p
LEFT JOIN xm_store_product sp ON p.id = sp.product_id
LEFT JOIN xm_store s ON sp.store_id = s.id
WHERE
s.id = 1
ORDER BY
p.type,
p.name asc
LIMIT
20 OFFSET 0
此查询非常慢:Querytime 2.532s
如果我删除Order By子句,查询速度非常快:0.0001s
解释显示以下信息:
+----+-------------+-------+--------+-------------------------------------------+----------------------+---------+---------------------------------------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-------------------------------------------+----------------------+---------+---------------------------------------+--------+----------------------------------------------+
| 1 | SIMPLE | s | const | PRIMARY | PRIMARY | 4 | const | 1 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | sp | ref | IDX_CA42254AB092A811,IDX_CA42254A4584665A | IDX_CA42254AB092A811 | 5 | const | 102157 | Using where |
| 1 | SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 4 | model.sp.product_id | 1 | |
+----+-------------+-------+--------+-------------------------------------------+----------------------+---------+---------------------------------------+--------+----------------------------------------------+
3 rows in set
我有3张桌子:
我尝试在p.name和p.type上添加索引以及组合索引(p.name,p.type),但它没有帮助。
如何优化此查询的效果?
编辑:
我花了2个小时创建了一个sqlfidle。但这里有一些数据。 http://sqlfiddle.com/#!2/2bf8d/1
问题是“分组依据”导致“使用索引;使用临时;使用filesort”。
我如何更正我的例子?
编辑2:
De xm_products表有大约200'000条记录。 xm_store_products大约400'000。查询用于寻呼机,每页限制为20个。
答案 0 :(得分:1)
在积极的反馈之后,我会把它作为答案:)
表现出(明显的)性能差异很有意义。
我不知道你的桌子有多大,但LIMIT 20只会在没有订单的情况下提高性能。 使用order by,所有记录首先必须在订单发生之前检索,而没有订单,执行在20次匹配后停止。
也许你的order-by-clause上有一个综合索引,并且你可以获得性能。
答案 1 :(得分:0)
您的问题是MySQL优化器是基于成本的。
因此,在这种情况下,它计算了访问表的最佳方案MySQL已经选择了错误的顺序..因为基于等待时间,磁盘i / o比CPU周期更昂贵..
您对表产品(p.type,p.name asc)进行排序,但此表在解释计划中最后访问,因此MySQL需要构建一个临时表“使用临时”来保存结果..并且因为结果未正确排序需要额外的快速排序“使用filesort”..
您可以使用STRAIGHT_JOIN进行测试,以便“绕过”MySQL优化器注意如果表中不存在s.id = 1,这可能会产生负面的性能结果...
SELECT
STRAIGHT_JOIN
p.id,
p.name,
p.sku,
p.type
FROM
xm_products p
LEFT JOIN xm_store_product sp ON p.id = sp.product_id
LEFT JOIN xm_store s ON sp.store_id = s.id
WHERE
s.id = 1
ORDER BY
p.type,
p.name asc
LIMIT
20 OFFSET 0
请注意,如果您还共享create table语句输出,则可能有更好的选项请参阅MySQL slow query using filesort ...如果s.id始终为1条记录,则可以使用派生表方法注释您可能需要添加新索引