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;
我有两个表:
类别 - 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;