Мета-ответ (комментарий на двух предыдущих ответов):
Использование IN имеет тенденцию деградировать к чему-то очень, как OR (дизъюнкция) всех членов в IN. Плохая работа.
Выполнение левого соединения и поиск нулевого значения - это улучшение, но это обскурантист. Если мы можем сказать, что мы имеем в виду, скажем, это в Вау, что это clossest, как мы бы сказали это на естественном языке:
select f.name
from family f left join genus g on f.id = g.family_id
WHERE NOT EXISTS (select * from species c where c.id = g.id);
Мы хотим, чтобы где-то не существует, поэтому, если мы можем сказать «, где не существует ", тем лучше. И, select *
в подзапросе не означает, что он действительно возвращает целую строку, поэтому это не «оптимизация», чтобы заменить select *
на select 1
, по крайней мере, на каких-либо современных СУБД.
Кроме того, если семья имеет много родов (и в биологии, большинство семейств), мы собираемся получить один ряд (семья, род), когда все, о чем мы заботимся, это семья. Итак, давайте сделаем один ряд для каждой семьи:
select DISTINCT f.name
from family f left join genus g on f.id = g.family_id
WHERE NOT EXISTS (select * from species c where c.id = g.id);
Это все еще не оптимально. Зачем? Ну, он выполняет требование OP, поскольку он находит «пустые» роды, но он не может найти семьи, у которых нет родов, «пустых» семейств. Можем ли мы заставить это сделать это тоже?
select f.name
from family f
WHERE NOT EXISTS (
select * from genus g
join species c on c.id = g.id
where g.id = f.id);
Мы можем даже избавиться от отдельных, потому что мы не присоединяемся к семье ни к чему. И это - оптимизация.
Комментарий от OP:
Это было очень ясное объяснение. Тем не менее, мне любопытно, почему использование IN или disjunctions плохо для производительности. Можете ли вы рассказать об этом или указать мне на ресурс, где я могу узнать больше об относительной производительности нескольких операций БД?
Подумайте об этом таким образом. Скажем, что в SQL не было оператора IN. Как вы подделали IN?
К серии ОШ:
where foo in (1, 2, 3)
эквивалентно
where (foo = 1) or (foo = 2) or (foo = 3)
Хорошо, скажете вы, но это еще не говорит мне, почему это плохо. Это плохо, потому что часто нет подходящего способа использовать ключ или индекс, чтобы посмотреть это. Таким образом, вы получаете либо а) сканирование таблицы, где для каждой дизъюнкции (или предиката или элемента списка IN) строка тестируется, пока тест не будет истинным или список не будет исчерпан. Или б) вы получите сканирование таблицы для каждого из этих дизъюнкций. Второй случай (б) может быть на самом деле лучше, поэтому вы иногда видите отборное с OR превратился в один выбор для каждого этапа ИЛИ union'd вместе:
select * from table where x = 1 or x = 3 ;
select * from table where x = 1
union select * from table where x = 3 ;
Теперь это не означает, вы никогда не сможете использовать список OR или IN. И в некоторых случаях оптимизатор запросов достаточно умен, чтобы превратить список IN в соединение - и другие ответы, которые вам были предоставлены, - это именно те случаи, когда это наиболее вероятно.
Но если мы можем явно включить наш запрос в объединение, нам не нужно задаваться вопросом, является ли оптимизатор запросов умным. И в общем, объединения - это то, что лучше всего использует databse.
[Таблицы таксономии в mysql] (http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/) отличная статья только на этом. [StackOverFlow] (http://stackoverflow.com/questions/4048151/what-are-the-options-for-storing-hierarchical-data-in-a-relational-database) - что-есть-опции для -storing-hierarchical-data-in-a-relational-database – rd42