【发布时间】:2012-02-11 17:25:53
【问题描述】:
我有两个通过第三个连接表进行多对多关联的表:产品和类别。每个产品可以属于多个类别。这是典型的多对多关系:
products
-------------
id
product_name
categories
-------------
id
category_name
products_to_categories
-------------
product_id
caregory_id
我希望允许用户搜索产品,这些产品属于某些选定的类别,而不是同时属于其他选定的类别。
示例:查找属于“计算机”和“软件”类别但不属于“游戏”、“编程”和“教育”类别的所有产品。
这是我为此设计的查询:
SELECT product_name
FROM products
WHERE
EXISTS (SELECT product_id FROM products_to_categories WHERE category_id = 1 AND product_id = products.id)
AND EXISTS (SELECT product_id FROM products_to_categories WHERE category_id = 2 AND product_id = products.id)
AND NOT EXISTS (SELECT product_id FROM products_to_categories WHERE category_id = 3 AND product_id = products.id)
AND NOT EXISTS (SELECT product_id FROM products_to_categories WHERE category_id = 4 AND product_id = products.id)
AND NOT EXISTS (SELECT product_id FROM products_to_categories WHERE category_id = 5 AND product_id = products.id)
ORDER BY id
它有效。但它非常慢,以至于我无法在生产中使用它。所有索引都已就位,但此查询会产生 5 个相关子查询并且表很大。
有没有办法在不依赖子查询的情况下解决相同的任务或以其他方式优化此查询?
更新
索引是:
products: PRIMARY KEY (id)
categories: PRIMARY KEY (id)
products_to_categories: PRIMARY KEY (product_id, caregory_id)
所有表都是 InnoDB
【问题讨论】:
-
EXISTS 很慢,因为它会查看每个值。尝试限制您获得的结果并添加“更多按钮”或其他技术。
-
@Silver Light:“索引已到位”。你有什么索引? (尤其是在
products_to_categories表中) -
尝试添加
(caregory_id, product_id)索引。它对您查询的任何版本(以及您将来可能进行的其他搜索)都有帮助。
标签: mysql many-to-many innodb sql-optimization