2011-09-14 9 views
9

Mam dwie tabele. Formularze mają ~ 77000 wierszy. Dzienniki mają ~ 2,7 miliona wierszy.Operator SQL "<>" jest bardzo wolny w porównaniu do "=" w tabeli z kilkoma milionami wierszy

Następująca kwerenda zwraca "30198" w mniej niż sekundę:

SELECT COUNT(DISTINCT logs.DOCID) FROM logs, forms WHERE logs.DOCID = forms.DOCID; 

I ta kwerenda została uruchomiona przez ~ 15 minut, tak daleko, a jeszcze nie skończył:

SELECT COUNT(DISTINCT logs.DOCID) FROM logs, forms WHERE logs.DOCID <> forms.DOCID; 

Dlaczego zapytanie "nie równe" jest znacznie wolniejsze?

+0

Co powiesz na "WHERE NOT logs.DOCID = forms.DOCID"? –

+1

Czy próbujesz znaleźć wartości 'logs.DOCID', dla których nie istnieje odpowiednia wartość w' forms'?Jeśli tak, spróbuj 'WYBIERZ COUNT (*) Z (WYBIERZ DOCID Z logów Z WYJĄTKIEM WYBIERZ DOCID z formularzy) T' –

+0

@Martin - zapytanie wróciło po 8 sekundach. Dzięki! –

Odpowiedz

27

Ponieważ = redukuje operację łączenia do jednego pasującego wiersza z każdej tabeli (zakładając, że te docody są unikatowe).

myśleć w ten drodze, masz tańczyć z 5 chłopców i 5 dziewczynek:

Adam  Alice 
Bob  Betty 
Charly Cathy 
Dick  Deb 
Evan  Elly 

sparować je przez pierwszego listu. Więc

Adam->Alice 
Bob->Betty 
etc... 

Jeden parowanie

Ale jeśli powiązać je przez „pierwsze litery nie pasują”, możesz skończyć z:

Adam->Betty 
Adam->Cathy 
Adam->Deb 
Adam->Elly 
Bob->Alice 
etc... 

już znacznie zwiększyła liczbę parowania. Właśnie dlatego Twoje zapytanie <> trwa tak długo. Zasadniczo próbujesz pobrać wiersze m x n, a nie tylko min(m,n). Dzięki tym danym otrzymasz 25 wierszy, a nie 5. Dla podanych rozmiarów tabel pracujesz z 77 000 * 2 700 000 = 207,9 miliardów wierszy, minus 77 000, gdzie te dwa pasują do siebie, łącznie 207,899,923,000 wierszy w połączony zestaw danych.


podane twoje wymagania zapytań, spróbuj lewy dołączyć i szukać zerowych rekordów prawy bok:

SELECT DISTINCT logs.DOCID 
FROM logs 
LEFT JOIN forms ON logs.DOCID = forms.DOCID 
WHERE forms.DOCID IS NULL 
+2

+1 Zgaduję, że OP prawdopodobnie potrzebuje "NOT IN" lub "NOT EXISTS" lub "EXCEPT" –

+0

Dzięki! Nic nie mogę zrobić, aby zoptymalizować moje zapytanie? Poszukuję wszelkich identyfikatorów formID w tabeli dzienników, które nie odpowiadają identyfikatorom formID w tabeli formularzy. Myślę, że znam odpowiedź, znajdując delta COUNT (DISTINCT logs.formID) i COUNT (DISTINCT logs.formID) WHERE logs.formID = forms.formID –

+1

@Tredman - użyj 'EXISTS' lub' IN' dla tego sprawdzenia – JNK

2

dwóch powodów:

  • zapytania dotyczące równoważności można zazwyczaj używają indeksów (jeśli jest dostępna), podczas gdy zapytanie o brak równości nie może być

  • <> zwraca o wiele więcej danych.

Twoje zapytanie z <> jest nieprawdziwe. Co powinien powrócić?

+0

Dzięki za odpowiedź. Powinien powrócić ~ 3800. Poszukuję wszelkich identyfikatorów formID w tabeli dzienników, które nie odpowiadają identyfikatorom formID w tabeli formularzy. Ktoś inny odpowiedział powyżej - powinienem używać "EXISTS" lub "IN". –

+1

Tak. Inną możliwością byłoby "RIGHT OUTER DOŁĄCZ" z 'IS NULL'. – jpalecek

1

Jest to całkowicie zależne od rozkładu wartości w tabeli. Jeśli kolumna, której szukasz, ma na przykład tę samą wartość: (= forms.DOCID) dla 99,99% wierszy i tylko jeden wiersz z inną wartością, zobaczysz dokładnie odwrotne zachowanie.

Powiązane problemy