简体   繁体   English

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

[英]MySQl Query: Join and Group By, slow performance

I have a problem with a MySQL Query and I'm not able to optimize it. 我有一个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

This Query is very slow: Querytime 2.532s 此查询非常慢:Querytime 2.532s

If I remove the Order By clause, the query is very fast: 0.0001s 如果我删除Order By子句,查询速度非常快:0.0001s

Explain show the following information: 说明显示以下信息:

+----+-------------+-------+--------+-------------------------------------------+----------------------+---------+---------------------------------------+--------+----------------------------------------------+
| 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

I have 3 tables: 我有3张桌子:

  • xm_product with primary key id 带主键ID的xm_product
  • xm_store with primary key id 带主键ID的xm_store
  • xm_store_product with index on store_id and product_id xm_store_product,其中包含store_id和product_id上的索引

I tried adding an index on p.name and p.type and also a combined index (p.name, p.type) but it did not help. 我尝试在p.name和p.type上添加索引以及组合索引(p.name,p.type),但它没有帮助。

How can I optimize the performance of this query? 如何优化此查询的性能?

EDIT: 编辑:

I took me 2 hours to create a sqlfidle. 我花了2个小时创建了一个sqlfidle。 But here it is with some data in it. 但这里有一些数据。 http://sqlfiddle.com/#!2/2bf8d/1 http://sqlfiddle.com/#!2/2bf8d/1

The problem is the "Group By" causing "Using index; Using temporary; Using filesort". 问题是“分组依据”导致“使用索引;使用临时;使用filesort”。

How can I correct my example? 我怎样才能纠正我的例子?

EDIT 2: 编辑2:

De xm_products table has about 200'000 records. De xm_products表有大约200'000条记录。 The xm_store_products about 400'000. xm_store_products大约400'000。 The Query is for a pager, the limit to 20 ist per page. 查询用于寻呼机,每页限制为20个。

I'll put it as an answer after the positive feedback :) 在积极反馈后我会把它作为答案:)

That there is a (noticable) difference in performance makes a lot of sense. 表现存在(明显的)差异很有意义。

I don't know how big your tables are, but a LIMIT 20 will only increase performance without an order by. 我不知道你的桌子有多大,但LIMIT 20只会在没有订单的情况下提高性能。 With the order by, all records will first have to be retrieved before the order by can happen, whereas without the order by, execution stops after 20 matches. 使用order by,所有记录首先必须在订单发生之前检索,而没有订单,执行在20次匹配后停止。

Maybe with a combined index on your order-by-clause and a view on that you could gain performance. 也许在你的order-by-clause上有一个综合索引,你可以获得性能。

Your problem is that the MySQL optimizer is cost based. 您的问题是MySQL优化器是基于成本的。

So it calculates the best plan for accessing your tables in this case MySQL has choosen the wrong order.. because disk i/o is more expensive vs CPU cycles based on wait times.. 所以它计算了访问表的最佳计划,在这种情况下,MySQL选择了错误的顺序..因为磁盘i​​ / o比基于等待时间的CPU周期更昂贵。

You sort on table product (p.type, p.name asc) but this table is accessed last in the explain plan so MySQL needs to build an temporary table "Using temporary" to hold the results.. and because the results are not correctly sorted an extra quicksort "using filesort" is needed.. 您对表产品(p.type,p.name asc)进行排序,但此表在解释计划中最后访问,因此MySQL需要构建一个临时表“使用临时”来保存结果..并且因为结果不正确需要额外的快速排序“使用filesort”...

You can test with STRAIGHT_JOIN so the MySQL optimizer is "bypassed" note this may give negative performance results if s.id = 1 not exists in the table... 您可以使用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

Note there may be better options if you also share the create table statement output see MySQL slow query using filesort ... If s.id is always 1 record you can use the derived table approach note you may need add an new index 请注意,如果您还共享create table语句输出,可能有更好的选项请参阅使用filesort的MySQL慢查询 ...如果s.id始终是1条记录,您可以使用派生表方法注意您可能需要添加新索引

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM