我有两张桌子:
类别 - 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秒,有人能告诉我如何改进吗?
答案 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;