MySQl查询:加入和分组,性能降低

时间:2013-11-15 11:41:55

标签: mysql performance

我的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张桌子:

  • 带主键ID的xm_product
  • 主键为
  • 的xm_store
  • xm_store_product,其索引位于store_id和product_id

我尝试在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个。

2 个答案:

答案 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条记录,则可以使用派生表方法注释您可能需要添加新索引