Mysql 自身和其他 table 性能的多个连接

Mysql multiple joins on self and other table performance

我有两个表:

类别 - ID - parent_id

categories_products - product_id - category_id

类别大约有 80 个条目,categories_products 大约有 20'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 秒,谁能告诉我如何改进它?

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

查询可以

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 exists.Number 行的索引解释计划会更多,但如果使用索引,则查询会 运行 更快 :)

基于@ABC 的建议:

  • 删除不需要的连接
  • 去掉LEFT
  • 使用UNION DISTINCT代替GROUP BY
  • 添加括号以防万一你在最后添加一些东西(它应该属于最后一个 SELECT 而它应该属于 UNION。

      ( 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?它似乎没有给table带来任何好处。我希望这会给你相同的结果集:

SELECT id AS cat_id FROM  categories;