Как я могу выполнить SQL-запрос NOT IN быстрее? - PullRequest
13 голосов
/ 10 февраля 2012

У меня есть таблица (EMAIL) адресов электронной почты:

EmailAddress
------------
jack@aol.com
jill@aol.com
tom@aol.com
bill@aol.lcom

и таблица (BLACKLIST) адресов электронной почты, занесенных в черный список:

EmailAddress
------------
jack@aol.com
jill@aol.com

, и я хочу выбрать эти адреса электронной почтыадреса, которые находятся в таблице EMAIL, но НЕ в таблице BLACKLIST.Я делаю:

SELECT EmailAddress
FROM EMAIL
WHERE EmailAddress NOT IN
   (
      SELECT EmailAddress
      FROM BLACKLIST
   )

, но когда количество строк становится очень высоким, производительность ужасна.

Как мне лучше это сделать? (Предположим, универсальный SQL, если это возможно. Если нет, предположим, T-SQL.)

Ответы [ 3 ]

29 голосов
/ 10 февраля 2012

Вы можете использовать левое внешнее соединение или предложение not exists.

Левое внешнее соединение:

select E.EmailAddress
  from EMAIL E left outer join BLACKLIST B on (E.EmailAddress = B.EmailAddress)
 where B.EmailAddress is null;

Не существует:

select E.EmailAddress
  from EMAIL E where not exists
         (select EmailAddress from BLACKLIST B where B.EmailAddress = E.EmailAddress)

Оба являются довольно общими решениями SQL (не зависят от конкретного механизма БД).Я бы сказал, что последний немного более производительный (хотя и ненамного).Но определенно более производительный, чем not in.

Как отмечалось в комментариях, вы также можете попробовать создать индекс на BLACKLIST(EmailAddress), который должен помочь ускорить выполнение вашего запроса.

4 голосов
/ 12 февраля 2012

NOT IN отличается от NOT EXISTS, если черный список допускает нулевое значение в качестве EmailAddress. Если есть одно нулевое значение, результат запроса всегда будет возвращать ноль строк, потому что NOT IN (null) неизвестно / ложно для каждого значения. Таким образом, планы запросов немного отличаются, но я не думаю, что это окажет какое-либо серьезное влияние на производительность.

Рекомендуется создать новую таблицу с именем VALIDEMAIL, добавить триггер в BLACKLIST, который удаляет адреса из VALIDEMAIL при вставке строк, и добавить в VALIDEMAIL при удалении из BLACKLIST. Затем замените EMAIL на представление, которое объединяет VALIDEMAIL и BLACKLIST.

1 голос
/ 11 июня 2019
select E.EmailAddress
  from EMAIL E where not exists
         (select EmailAddress from BLACKLIST B where B.EmailAddress = E.EmailAddress)

Равно (Кстати, есть, вероятно, владелец)

select EmailAddress from mail.EMAIL 
EXCEPT
select EmailAddress from mail.BLACKLIST 

даст вам строки, которые отличаются, даже если NULL в EmailAddress

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...