У меня есть две таблицы, связанные со многими ко многим через третью соединительную таблицу: товары и услуги. Каждый продукт может быть в нескольких категориях. Это типичный многие-ко-многим realationship:Эффективный поиск во многих связанных друг с другом таблицах
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
Он работает. Но это так невероятно медленно, что я просто не могу использовать его в производстве. Все idexes на месте, но этот запрос приводит к 5 зависимым подзапросам, а таблицы огромны.
Есть ли способ решить одну и ту же задачу без зависимых подзапросов или оптимизировать этот запрос каким-либо другим способом?
UPDATE
Индексы:
products: PRIMARY KEY (id)
categories: PRIMARY KEY (id)
products_to_categories: PRIMARY KEY (product_id, caregory_id)
Все таблицы InnoDB
EXISTS медленный, потому что он смотрит на каждое значение. Попытайтесь ограничить полученные результаты и поместите «больше кнопки» или другую технику. – AlfredoVR
@Silver Light: «индексы на месте». Какие индексы у вас есть? (особенно в таблице 'products_to_categories') –
Попробуйте добавить индекс' (caregory_id, product_id) '. Это действительно поможет с любой версией вашего запроса (и с другими поисковыми запросами, которые могут возникнуть у вас). –