JOIN вместо подзапроса для связанных тегов

У меня есть три таблицы: bookmarks, tag и tagging. tagging — это таблица ассоциаций для связывания тегов с закладками. Я хотел бы выбрать связанные теги. Текущий запрос выполняется целую вечность, но я не мог понять JOIN, которые могли бы заменить подзапрос, который выбирает все связанные закладки, помеченные определенными идентификаторами тегов.

SELECT ta.name, count(*) 
FROM tagging t2 
JOIN tag ta ON t2.tag_id=ta.id  
WHERE t2.bookmark_id IN (
   SELECT bookmark_id 
   FROM tagging t1 
   WHERE t1.tag_id IN (1, 7) 
   GROUP BY t1.bookmark_id 
   HAVING COUNT(t1.id) = 2
) 
GROUP BY ta.id

Вот результат EXPLAIN этого запроса:

1   PRIMARY            ta  index PRIMARY    PRIMARY         8   NULL         3   
1   PRIMARY            t2  ref   tag_id_idx tag_id_idx      8   blinkz.ta.id 89   Using where
2   DEPENDENT SUBQUERY t1  index tag_id_idx bookmark_id_idx 8   NULL         71   Using where 

У меня есть индекс для полей bookmark_id и tag_id в таблице tagging. Таблица tag имеет первичный ключ с именем id.

Как можно оптимизировать этот запрос, желательно с помощью JOIN вместо подзапроса?


person chiborg    schedule 19.12.2010    source источник


Ответы (1)


Низкая производительность вызвана ошибкой в ​​MySQL, которая, надеюсь, скоро будет исправлена. А пока попробуйте это:

SELECT tag.name, COUNT(*) AS cnt
FROM tagging T1
JOIN tag
ON T1.tag_id = tag.id  
JOIN (
   SELECT bookmark_id 
   FROM tagging
   WHERE tag_id IN (1, 7) 
   GROUP BY bookmark_id 
   HAVING COUNT(id) = 2
) T2
ON T1.bookmark_id = T2.bookmark_id
GROUP BY tag.id

Я предполагаю, что на (bookmark_id, tag_id) есть уникальное ограничение.

person Mark Byers    schedule 19.12.2010
comment
Это прекрасно работает! Однако есть одна небольшая ошибка: HAVING должен быть COUNT(tagged.id) вместо COUNT(T1.id) - person chiborg; 19.12.2010
comment
@chiborg: Спасибо, исправлено. Кстати, если поле id НЕ NULL (что, вероятно, так и есть), то вместо этого вы можете просто написать COUNT(*). - person Mark Byers; 19.12.2010