Join between mapping (junction) table with specific cardinality

У меня есть простой вопрос о наиболее эффективном способе выполнения определенного соединения.

Возьмем три таблицы, реальные имена изменены для защиты невинных:

Таблица: animal

animal_id   name   ...
======================
1           bunny
2           bear
3           cat
4           mouse

Таблица: tags

tag_id     tag
==================
1          fluffy
2          brown
3          cute
4          small

Mapping Table: animal_tag

animal_id   tag_id
==================
1           1
1           2
1           3
2           2
3           4
4           2

Я хочу найти всех животных, которые помечены как 'пушистые', 'коричневые' и 'милые'. То есть животное должно быть помечено всеми тремя. В реальности количество необходимых меток может варьироваться, но для данного обсуждения это не имеет значения. Вот запрос, который я придумал:

SELECT * FROM animal
JOIN (
      SELECT at.animal_id FROM animal_tag at
      WHERE at.tag_id IN (
                          SELECT tg.tag_id FROM tag tg
                          WHERE tg.tag='fluffy' OR tg.tag='brown' OR tg.tag='cute'
                          )
      GROUP BY at.animal_id HAVING COUNT(at.tag_id)=3
      ) AS jt
ON animal.animal_id=jt.animal_id

На таблице с тысячами "животных" и сотнями "меток" этот запрос работает достаточно быстро... 10 десятков миллисекунд. Однако, когда я смотрю на план запроса (в качестве БД используется Apache Derby), расчетная стоимость оптимизатора довольно высока (9945.12), а план довольно обширен. Для такого "простого" запроса я обычно стараюсь получить план запроса с оценочной стоимостью в одно- или двузначных числах.

Поэтому мой вопрос заключается в том, есть ли лучший способ выполнить этот запрос? Кажется, что это простой запрос, но я не смог придумать ничего лучше.

6
задан Evan Teran 1 March 2012 в 01:46
поделиться