2009-09-18 10 views
6

mam tej klauzuli sprzężenia w procedurze przechowywanej odziedziczyłem:T-SQL ISNULL() Optymalizacja

WHERE a.is_active = 1 
AND b.due_date <= ISNULL(@due_date_limit, b.due_date) 

Jak bym ponownie napisać to, aby usunąć ISNULL jak to powoduje poważne problemy z wydajnością?

+0

SQL Server wersja? – AnthonyWJones

Odpowiedz

7

w tym wypadku musiałbym if, sprawdzając @due_date_limit

IF (@due_date_limit IS NULL) 
BEGIN 
    ... 
    WHERE a.is_active = 1 --not required to compare b.due_date <= b.due_date 
END 
ELSE 
BEGIN 
    ... 
    WHERE a.is_active = 1 
    AND  b.due_date <= @due_date_limit 
END 
2
AND @due_date_limit IS NULL OR b.due_date <= @due_date_limit 

, ale nie jestem pewien, czy byłby o wiele szybszy.

+0

Jeśli istnieje indeks, to jest. – recursive

+0

Indeks nie jest problemem - nawet gdyby istniał, indeks byłby używany tylko w 2. połowie. Jest o wiele lepszy niż sugestie ISNULL/COALESCE. –

1

@due_date_limit jest przechowywany zmienny procedura może więc być zbitek od tego zapytania wszyscy razem:

if (@due_date_limit is NULL) 
    <run query that works when @due_date_limit is NULL> 
else 
    <run query that works when @due_date_limit is NOT NULL> 
1
COALESCE(@due_date_limit, b.due_date) 

może pomóc

+0

To będzie działać z wdziękiem, ale to marnotrawstwo, aby wykonać równoważnik 1 = 1. –

2

ma indeks na DUE_DATE? Jeśli nie, dodaj jeden, a następnie sprawdź wydajność. Jeśli istnieje już jest, a następnie zmienić na dwóch oddzielnych sprawozdaniach

If @due_date_limit is null 
    Select [stuff] 
    From Table 
    Else 
    Select [stuff] 
    From Table 
    Where b.due_date <= @due_date_limit 

jednak sprawę, że nie filtrowany (gdy @due_date_limit jest null) lub filtrowanie za pomocą < = potencjalnie mogą wrócić znaczną liczbę rekordów, które wyeliminuje każdą okazję do korzystania z indeksu i będzie wymagać pełnego skanowania tabeli. To może być to, czego doświadczasz.

3

Najczęstszą przyczyną słabej wydajności tego typu zapytania jest to, że optymalizator nie może być pewien, jaka wartość typowa dla @due_date_limit będzie dotyczyła większości zapytań. Często plan generowany i ponownie wykorzystywany przez kolejne egzekucje faworyzuje przypadek, w którym wartość jest zerowa.

Począwszy od SQL 2005 można kierować Optymalizator pomocą „optymalizacji dla” opcji: -

WHERE a.is_active = 1 
AND b.due_date <= ISNULL(@due_date_limit, b.due_date) 
OPTION (OPTIMIZE FOR (@due_date_limit = '09/01/2009')) 
+0

Jeśli parametr ma wartość NULL, dlaczego nadal chcesz porównywać wartości? Nie, więc nie używaj ISNULL/COALESCE dla opcjonalnych parametrów. –

0

Od @due_date_limit jest zmienna procedura przechowywana, można po prostu sprawdzić, czy nie NULL przed zapytania i ustawić go do wartości domyślnej, jeśli zajdzie taka potrzeba, eliminując w ten sposób kontrolę ISNULL w klauzuli WHERE.

IF (@due_date_limit IS NULL) 
BEGIN 
    SET @due_date_limit = '09/01/2009'; 
END 

i wówczas klauzula WHERE po prostu wyglądać następująco:

WHERE a.is_active = 1 
AND b.due_date <= @due_date_limit 
+0

Odpowiedź astandera jest lepszym rozwiązaniem, jeśli potrzebujesz, aby był taki sam jak rekord kolumny, aby spełnić warunek operatora '<=', w innym przypadku należy ustawić go przed takim zapytaniem, ponieważ będzie on szybszy i nie będzie czeku. – johntrepreneur