Mysql多重连接自我和其他表的性能

时间:2015-04-15 12:39:06

标签: mysql performance self-join

我有两张桌子:

类别  - ID   - parent_id

categories_products   - product_id   - category_id

类别有大约80个条目,categories_products大约20&000; 000。 我使用此查询加入了自己和categories_products的类别:

SELECT c0.id AS cat_id
FROM categories AS c0
LEFT JOIN categories AS c1 ON c0.id = c1.parent_id
LEFT JOIN categories AS c2 ON c1.id = c2.parent_id
LEFT JOIN categories_products ON  
  c0.id = categories_products.category_id
  OR c1.id = categories_products.category_id
  OR c2.id = categories_products.category_id
GROUP BY c0.id;

解释:

+------+-------------+---------------------+-------+------------------------------------+------------------------------------+---------+------------------+-------+--------------------------------------------------------------+
| id   | select_type | table               | type  | possible_keys                      | key                                | key_len | ref              | rows  | Extra                                                        |
+------+-------------+---------------------+-------+------------------------------------+------------------------------------+---------+------------------+-------+--------------------------------------------------------------+
|    1 | SIMPLE      | c0                  | index | NULL                               | fk_categories_parent_id            | 5       | NULL             |    86 | Using index; Using temporary; Using filesort                 |
|    1 | SIMPLE      | c1                  | ref   | fk_categories_parent_id            | fk_categories_parent_id            | 5       | preview_m2.c0.id |     3 | Using index                                                  |
|    1 | SIMPLE      | c2                  | ref   | fk_categories_parent_id            | fk_categories_parent_id            | 5       | preview_m2.c1.id |     3 | Using where; Using index                                     |
|    1 | SIMPLE      | categories_products | index | fk_categories_products_category_id | fk_categories_products_category_id | 4       | NULL             | 25273 | Using where; Using index; Using join buffer (flat, BNL join) |
+------+-------------+---------------------+-------+------------------------------------+------------------------------------+---------+------------------+-------+--------------------------------------------------------------+

查询大约需要1.5秒,有人能告诉我如何改进吗?

2 个答案:

答案 0 :(得分:1)

尝试联合所有而不是OR。使用union它可能会执行索引扫描,这将有助于更快地运行查询

查询可以是

  

SELECT c0.id AS cat_id
FROM categories AS c0
LEFT JOIN categories AS c1 ON c0.id = c1.parent_id
LEFT JOIN categories AS c2 ON c1.id = c2.parent_id
LEFT JOIN categories_products ON  
  c0.id = categories_products.category_id
  union all 
  SELECT c0.id AS cat_id
FROM categories AS c0
LEFT JOIN categories AS c1 ON c0.id = c1.parent_id
LEFT JOIN categories AS c2 ON c1.id = c2.parent_id
LEFT JOIN categories_products ON  
c1.id = categories_products.category_id
  union all 
 SELECT c0.id AS cat_id
FROM categories AS c0
LEFT JOIN categories AS c1 ON c0.id = c1.parent_id
LEFT JOIN categories AS c2 ON c1.id = c2.parent_id
LEFT JOIN categories_products ON c2.id = categories_products.category_id

我没有包括group by ..基于结果所需的group by可用于整个外部循环。这可能只有在categories_products.category_id上的索引存在的情况下才有用。解释计划中的行数会更多但是如果使用索引,则查询运行得更快:)

答案 1 :(得分:1)

以@ ABC的建议为基础:

  • 摆脱不必要的联接
  • 摆脱LEFT
  • 使用UNION DISTINCT代替GROUP BY
  • 添加parens以防万一你在最后添加某些内容(当它应该属于UNION时它将属于最后一个SELECT。

      ( SELECT  c0.id AS cat_id
            FROM  categories AS c0
            JOIN  categories_products ON c0.id = categories_products.category_id 
      )
    union  DISTINCT 
      ( SELECT  c0.id AS cat_id
            FROM  categories AS c0
            JOIN  categories AS c1 ON c0.id = c1.parent_id
            JOIN  categories_products ON c1.id = categories_products.category_id 
      )
    union  DISTINCT 
      ( SELECT  c0.id AS cat_id
            FROM  categories AS c0
            JOIN  categories AS c1 ON c0.id = c1.parent_id
            JOIN  categories AS c2 ON c1.id = c2.parent_id
            JOIN  categories_products ON c2.id = categories_products.category_id 
      ); 
    

为什么甚至提到categories_products?它似乎没有带来什么。我希望这会给你相同的结果集:

SELECT id AS cat_id FROM  categories;