Можем ли мы оптимизировать этот MySQL SELECT Query (2 вложенных SELECT и 2 INNER JOIN) - PullRequest
2 голосов
/ 01 ноября 2011
SELECT id,name,color
FROM animals a
INNER JOIN animal_tags atags ON atags.animal_id = a.id
WHERE atags.tag_id = 70 OR a.id IN (
SELECT a2.id FROM animals a2
WHERE a2.inherit_tags = 1 AND a2.species IN
(SELECT species.id FROM species
INNER JOIN species_tags stags ON stags.species_id = species.id
WHERE stags.tag_id = 70))

По сути, я ищу любое животное, которое имеет ассоциацию с tag_id 70 (скажем, «мех»), и любое животное, которое принадлежит к виду с ассоциацией tag_id 70 И где животное должно наследовать.это теги от вида.

Мой другой вариант - в основном убрать часть наследуемых тегов и просто всегда определять теги для животных ... но почему-то это не кажется очень нормализованным.(Обратите внимание, что таблицы * _tags просто содержат отношение, и каждый tag_id имеет связь с таблицей «tags», в которой хранятся подробности тега. Это не важно для этого запроса, но просто для того, чтобы показать вам, что моя схема таблицы полностью нормализована.)

Ответы [ 2 ]

2 голосов
/ 01 ноября 2011

Поскольку вам на самом деле не нужны значения из таблицы тегов в вашем наборе результатов, полное соединение не требуется.Часто оптимизатор запросов может более эффективно обрабатывать полусоединения, используя exists.

Кроме того, вы присоединяетесь к промежуточным таблицам (животные - виды - виды - теги), когда таблица видов не нужна, поскольку все три таблицы объединяются по видову_ид.Вы можете обходить виды и присоединяться от животных к видам тегов.

Наконец, так как вы уже используете таблицу животных и оцениваете условие ИЛИ, нет необходимости присоединять эту таблицу к себе.Это должно оказаться более эффективным.Я бы также позаботился о том, чтобы у вас были индексы tag_id, kind_id и т. Д.

SELECT id, name, color
FROM animals a
WHERE EXISTS(SELECT 1 
               FROM animal_tags atags 
               where atags.tag_id = 70 
                   and atags.animal_id = a.id) 
    OR (a.inherit_tags = 1 
        AND EXISTS( SELECT 1 from species_tags stags
                   WHERE stags.species_id = a.species 
                        AND stags.tag_id = 70
                 )
        )
2 голосов
/ 01 ноября 2011

Я считаю, что этот запрос должен быть эквивалентным.

SELECT id, name, color
    FROM animals a
        INNER JOIN animal_tags atags
            ON a.id = atags.animal_id
        LEFT JOIN species s
            INNER JOIN species_tags stags
                ON s.id = stags.species_id
                    AND stags.tag_id = 70
            ON a.species = s.id
                AND a.inherit_tags = 1
    WHERE atags.tag_id = 70
        OR s.id IS NOT NULL
...