2012-02-10 10 views
10

Mam tabeli (EMAIL) adresów e-mail:Jak wykonać kwerendę "NOT IN" SQL szybciej?

EmailAddress 
------------ 
[email protected] 
[email protected] 
[email protected] 
[email protected] 

i stół (czarna lista) na czarnej liście adresów e-mail:

EmailAddress 
------------ 
[email protected] 
[email protected] 

i chcę wybrać te adresy e-mail, które są w Tabela EMAIL, ale NIE w tabeli BLACKLIST. Robię:

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

ale gdy liczy się wiersz uzyskać bardzo wysoką wydajność jest straszne.

Jak mogę to zrobić lepiej? (W razie potrzeby przyjmij ogólny kod SQL. Jeśli nie, przyjmij T-SQL.)

+2

Dodaj indeks do kolumny BLACKLIST..EmailAddress, aby poprawić wydajność wybranego zapytania. – Tomek

+0

@ Tomek - Powinienem był wskazać, problemy z wydajnością są zawarte w indeksie. – Howiecamp

Odpowiedz

21

Możesz użyć lewego sprzężenia zewnętrznego lub klauzuli not exists.

Lewy sprzężenie zewnętrzne:

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

nie istnieje:

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

Zarówno są dość ogólne rozwiązania SQL (nie zależy od konkretnego silnika DB). Powiedziałbym, że ten drugi jest nieco bardziej wydajny (choć nie przez wiele). Ale zdecydowanie bardziej wydajne niż not in.

Zgodnie z komentarzami można również spróbować utworzyć indeks o numerze BLACKLIST(EmailAddress), który powinien przyspieszyć wykonanie zapytania.

+0

@dasblinkenlight: thanks! dodał to. –

+0

"Nie istnieje" może być szybsze w niektórych silnikach baz danych, ale AFAIK, SQL Server optymalizuje to automatycznie dla ciebie i konwertuje 'IN' na' NOT Exists' – Icarus

+0

Jeśli się nie mylę, to uważam, że 'left join' być wolniejszym, a "nie istnieje" wygeneruje taki sam plan kwerend, co zapytanie OP. –

3

NOT IN różni się od NOT EXISTS, jeśli czarna lista dopuszcza wartość pustą jako EmailAddress. Jeśli istnieje pojedyncza wartość pusta, wynik zapytania zawsze zwróci zero wierszy, ponieważ wartość NOT IN (null) jest nieznana/false dla każdej wartości. Plany kwerend w związku z tym różni się nieznacznie, ale nie sądzę, że miałoby to poważny wpływ na wydajność.

Proponuje się utworzenie nowej tabeli o nazwie VALIDEMAIL, dodanie wyzwalacza do BLACKLIST, który usuwa adresy z VALIDEMAIL po wstawieniu wierszy i dodawania do VALIDEMAIL po usunięciu z BLACKLIST. Następnie zastąp EMAIL widokiem, które jest połączeniem zarówno VALIDEMAIL, jak i BLACKLIST.

Powiązane problemy