НЕ СУЩЕСТВУЕТ
SELECT m."memberID",
m.lastname
FROM MEMBERS m
WHERE NOT EXISTS (SELECT NULL
FROM MEMBERS b
WHERE b.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*'
AND b."memberID" = m."memberID");
ВЛЕВО СОЕДИНЯЕТСЯ / НУЛЬ
SELECT m."memberID",
m.lastname
FROM MEMBERS m
LEFT JOIN MEMBERS b ON b."memberID" = m."memberID"
AND b.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*'
WHERE b."memberID" IS NULL
Резюме
Цитата :
PostgreSQL одинаково обрабатывает LEFT JOIN
и NOT EXISTS
, используя один и тот же план выполнения для обоих (а именно Hash Anti Join для примера выше).
Что касается NOT IN
, который семантически отличается, посколькуего логика трехвалентна, и он может возвращать NULL, PostgreSQL пытается принять это во внимание и ограничивается использованием фильтра против подплана (хешированный подплан для хешируемого набора результатов, как в примере выше).
Поскольку это необходимодля поиска в хеш-таблице каждого пропущенного значения дважды (первый раз, чтобы найти значение, второй раз, чтобы найти NULL), этот метод немного менее эффективен.
Простой подплан, к которому может прибегнуть оптимизаторвсякий раз, когда он решает, что список не помещается в память, он очень неэффективен, и следует избегать запросов, которые могут его использовать, как чуму.
Вот почему в PostgreSQL 8.4 один примерld всегда используйте LEFT JOIN / IS NULL
или NOT EXISTS
вместо NOT IN
для поиска пропущенных значений.
Addendum
Но, как отмечает Эндрю Лазарь, если нет дубликатовmemberid в таблице MEMBERS
, запрос должен быть только:
SELECT m."memberID",
m.lastname
FROM MEMBERS m
WHERE b.lastname ~* '[a-zA-z]+([-][a-zA-Z]+)*'