2011-12-21 6 views
5

Co jest lepszego w klauzuli WHERE?SQL GDZIE na dużym stole -> Najpierw dołącz do małego stołu lub umieść FK bezpośrednio w klauzuli WHERE?

Mam duży stół, z FK do małego stolika. Mogę przeszukiwać FK bezpośrednio lub mogę dołączyć do tabeli FK i ustawić ograniczenie WHERE dla połączonej tabeli. Co jest lepsze/lepsze?

Więc tak:

SELECT lt.* FROM LargeTable lt 
WHERE lt.SomeId in(12,55) 

Albo to:

SELECT lt.* FROM LargeTable lt 
INNER JOIN SmallTable st ON lt.SomeId=st.ItemId 
WHERE st.Id in(12,55) 


testowałem to z Set statistics time on, ale nie spodziewałem się tego wyniku. Kto może wyjaśnić, co się tutaj dzieje?

Pierwszy test bez dołączyć:

(946 row(s) affected) 
SQL Server Execution Times: 
    CPU time = 1544 ms, elapsed time = 1580 ms. 

drugie badanie z przyłączyć

(946 row(s) affected) 
SQL Server Execution Times: 
    CPU time = 2636 ms, elapsed time = 366 ms. 

EDIT: Kiedy zrobić SELECT Id zamiast SELECT *, następnie pierwsze zapytanie bez dołączyć ma niższą upływającego czasu, a koszt kwerendy w planie wykonania wynosi 25% dla braku łączenia kontra 75% dla zapytania z łączeniem.

+2

jest 'lt.Id' indeksowane? – RedFilter

+2

Powinieneś dołączyć rzeczywisty plan wykonania, a następnie uruchomić oba zapytania obok siebie ... SQL Server powie Ci, który z nich jest szybszy i dlaczego jest szybszy. –

+0

+1 za rzeczywisty plan wykonania. Nie musisz zgadywać. –

Odpowiedz

4

podstawie planów realizacyjnych, oba pytania są zasadniczo skanując każdy rekord w całym dużym stole ... drugie zapytanie jest po prostu znalezienie mały zestaw rekordów z małym stoliku przed skanowaniem dużego stołu, dlatego koszt względny dla obu wynosi 50%.

Polecam biorąc pod uwagę indeks na largeTable.SomeId, a następnie przejść z pierwszego zapytania:

SELECT lt.* FROM LargeTable lt 
WHERE lt.SomeId in(12,55) 

EDIT:

Więc pytanie brzmi dlaczego zapytań z dołączyć mają krótszy czas trwania niż zapytanie bez łączenia.

myślę Martin Smith dał odpowiedź na to pytanie:

Twój drugi dostaje równoległego planu pierwsza nie

Zauważysz, że twój pierwszy zapytanie miał krótszy czas procesora, ale dłuższy czas, który upłynął.Aby z grubsza podsumować, twoje pierwsze zapytanie wymagało mniej wysiłku, aby serwer mógł ukończyć, ale twoja druga kwerenda wykorzystała plan równoległy i zarejestrowała wiele procesorów do wykonania zapytania, więc ukończenie tego procesu zajęło mniej czasu, ale więcej wysiłku.

+1

Uzgodnione - Jeśli znasz już identyfikatory i nie potrzebujesz informacji (lub w jakikolwiek sposób ograniczasz wiersze), dlaczego Oczywiście, jeśli masz tylko identyfikatory, ponieważ wyciągnąłeś je trochę wcześniej (jak "SELECT id WHERE key = @ input"), możesz chcieć zmienić to ... –

+0

@ X-Zero: To był moja pierwsza myśl, ale potem dostałem te nieoczekiwane czasy, więc zastanawiałem się, co byłoby lepsze/szybsze. Zamierzam dodać indeks i zapomnieć o sprzęcie, ale zastanawiałem się, dlaczego. –

+0

@ErikDekker - To powinno być brane pod uwagę nie tylko jako perspektywa wydajności (która może się nieoczekiwanie zmienić z pozornie "niezwiązanych" przyczyn); jeśli dołączasz do stołu, spodziewałbym się, że z jakiegoś powodu jest ważny dla kontekstu - że próbujesz ograniczyć (lub pomnożyć) wyniki w pewien sposób lub pobrać niektóre dane. Jeśli żadna z tych rzeczy nie zostanie oczywiście wykonana, może wywołać niepokojące zamieszanie, że coś zostało pominięte. –

0

2 rzeczy do rozważenia:

  1. zrobił swoje wewnętrzne dołączyć powrócić mniejszy zbiór danych? w tym przypadku warunek twojego miejsca jest wykonywany na mniejszych rzędach.
  2. myślę w drugim zapytaniu chodziło powiedzieć gdzie st.Id w (12, 55), w tym przypadku, twój gdzie klauzula jest uruchomiony przed indeksem klucza podstawowego, który jest klastra, a więc o wiele szybciej niż Twój nieklastrowanym indeks klucza obcego
+0

1: oba dają mi 946 wierszy (patrz pytanie). 2: Tak, miałem na myśli to, zmodyfikowałem pytanie! (moje testy były dobre) –

+0

na końcu oba dają 946, ale zanim dojdziesz do klauzuli where, twój wynik się skurczył? zdarzyłoby się to, gdyby twój identyfikator lt.SomeId był zerowalny, w takim przypadku cały rekord bez lt.SomeId nie jest oceniany przez klauzul where.jeśli nie jest to zerowalne, to jedyną rzeczą, która pozostała, jest drugi punkt (wyszukiwanie w stosunku do klucza podstawowego jest szybsze niż wyszukiwanie z kluczem obcym, nawet po dodaniu kosztu połączenia –

+0

Ale czy będą one miały takie same wyniki? możliwe, aby mieć rekord w tabeli 1 o identyfikatorze 12, który nie jest również w tabeli2? Te dwa zapytania są funkcjonalnie różne.W drugim zapytaniu dane muszą istnieć w obu tabelach w pierwszym zapytaniu tylko w jednej tabeli – HLGEM

0
  1. Ponieważ oba zapytania wyodrębniają wyniki z dużej tabeli, jak wspomniano. Tak, czy masz Non clustered Index dla kolumny "SomeID"?

  2. Czy używasz wszystkich kolumn z tej tabeli. Jeśli tak nie jest. Zaleca się wymienianie tylko wymaganych kolumn.

  3. W obu zapytań są pobieranie danych z dużego stołu tak można to zrobić od pierwszego zapytania tylko z „Non indeksu klastrowego

  4. Jeżeli istnieje jakakolwiek sprawa dostać tylko dopasowane dane. Następnie możesz zrobić, jak poniżej również.

    Select ColumnName From 
    (
    Select ColumnName, SomeID from LargeTable Where SomeID in(12,13) 
    )T 
    Inner Join SmallTable T1 on T.SomeID = T1.SomeID 
    
  5. Jeśli chcesz bardzo szybkie wyniki. Możesz zrobić, jak poniżej.

    Create table #Large 
    (
        Id Int, 
        ColumnName Varchar(100) 
    ) 
    Insert into #Large(ID, ColumnNmae) 
    Select ColumnName, SomeID from LargeTable Where SomeID in(12,13) 
    

i wreszcie dołączyć

Select ColumnName From #Large T 
Inner Join SmallTable T1 on T.SomeID = T1.SomeID 

i bez Dołącz

Select ColumnName from #Large 
Powiązane problemy