Zmusić program SQL Server do uruchomienia warunków zapytania zgodnie z opisem?


14

Używam SQL Server 2008 R2 i mam tę pseudo-zapytanie (SP):

select ...
from ...
WHERE    @LinkMode IS NULL
     AND (myColumn IN (...very long-running query...))
     ...
     ...

Problem polega na tym, że zapytanie zajmuje bardzo dużo czasu - nawet jeśli uruchomię SP za pomocą @LinkMode=2.

Jak zauważyłeś, długo działające zapytanie powinno być wykonane tylko wtedy, gdy @LinkMode ma wartość null, co nie ma miejsca w tym przypadku. W moim przypadku @LinkMode = 2!

Jeśli jednak zmienię to na:

 select ...
    from ...
    WHERE    1=2
         AND (myColumn IN (...very long time exeted query...))
     ...
     ...

SP działa szybko.

Słyszałem wcześniej, że czasami optymalizator może zoptymalizować kolejność kryteriów.

Więc pytam :

  • Nawet jeśli optymalizator wybierze inną trasę, co może być szybsze niż sprawdzenie, czy =null? Myślę, że sprawdzanie if a==nulljest znacznie szybsze niż uruchamianie innych długich zapytań ...

  • Jak zmusić program SQL Server do uruchomienia zapytania w takiej formie, w jakiej go napisałem (ta sama kolejność)?

Odpowiedzi:


22

Wpadasz w pułapkę „ Catch-All Query ”, którą bardzo dobrze wyjaśnia Gail Shaw .

Podsumowując problem: SQL Server optymalizuje znaczne obciążenie kompilacji zapytań, buforując plan zapytań po kompilacji, a następnie sprawdzając w pamięci podręcznej odpowiedni plan zapytań przed późniejszą kompilacją. Występujące tutaj „dopasowanie” ma charakter czysto tekstowy, więc rzeczywista wartość zmiennej nie wpłynie na to.

To dobrze 99% czasu, ale w niektórych przypadkach jest źle . Przykładem może być sytuacja, gdy ktoś próbuje skonstruować klauzulę WHERE, tak jakby to było jak zwarcie instrukcji IF w C itp. To nie działa dobrze, ponieważ kompilator SQL musi stworzyć jeden plan zapytań, który będzie działał niezależnie rzeczywistych wartości parametrów i jedynym sposobem, w jaki może poradzić sobie z tymi „sprytnymi” logicznymi warunkami przełączania w klauzuli WHERE, jest stworzenie prostego planu brutalnej siły, który po prostu skanuje całą tabelę, filtrując wiersze w miarę jej przechodzenia , bez wykorzystywania żadnych indeksów.

Nic dziwnego, że powoduje to, że są one jednolicie wolne, bez względu na wartości parametrów / zmiennych.


8

Nie ma gwarantowanego sposobu zmuszenia serwera SQL do wykonania warunków klauzuli w określonej kolejności. Optymalizator zawsze ocenia je w kolejności, w jakiej uzna to za stosowne.

Możesz zrobić coś takiego:

IF @LinkMode IS NULL
BEGIN
    select ...
    from ...
    WHERE (myColumn IN (...very long time exeted query...))
         ...
         ...
END
ELSE
BEGIN
    select ...
    from ...
    WHERE ...
         ...
END

3

Jeśli jest to opcja, użyj instrukcji JEŻELI, aby wykonać odpowiednią formę zapytania. Ponadto w SQL mówisz silnikowi db, co robić, a nie jak to zrobić - rzeczy nie są wykonywane od początku do końca. Trudno jest przewidzieć, co dokładnie zrobi. Prawdopodobnie o tym wiesz;)


2

Dynamiczny SQL prawdopodobnie też by działał, ponieważ w takim przypadku optymalizator zapytań powinien uzyskać rzeczywiste wartości w czasie wykonywania (popraw mnie, jeśli się mylę, w rzeczywistości nie jestem pewien, ale wydaje mi się, że pamiętam używanie go w podobnych sytuacjach) . Ale ja jestem z innymi w tym, że klauzula IF / ELSE będzie ci najlepiej służyć, ponieważ jest to najprostsze i najłatwiejsze rozwiązanie, które zrobi dokładnie to, co jest potrzebne.

W celu wykorzystania w przyszłości, jeśli jeszcze go nie używałeś, okropnie brzydka witryna z działającym przykładem dynamicznego SQL można znaleźć na przykład: http://sqlusa.com/bestpractices/dynamicsql/


1

Poleciłbym konstrukcję IF / ELSE. Jeśli z jakiegokolwiek powodu, który Ci nie odpowiada, zawsze możesz rozważyć użycie opcji Z RECOMPILE ..


Czy mógłbyś rozwinąć kwestię tego, jak może wyglądać konstrukcja „if / else”? : D
jcolebrand

Chciałem zasugerować użycie OPCJI (Z RECOMPILE), ponieważ za każdym razem wygenerowałoby to idealny plan - opóźnienie kompilacji spowodowałoby dodatkowe obciążenie, ale podejrzewam, że ogólnie lepiej w tym przypadku.
SqlRyan
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.