2013-04-06 27 views
5

Mamy wiele "przeszukiwanych procedur przechowywanych", które pobierają wiele parametrów zerowalnych do wyszukiwania wierszy danych w różnych tabelach. Oni zwykle zbudowany tak:T-SQL - używany jest plan nieoptymalny - klauzula WHERE powinna zostać skrócona

SELECT  * 
FROM  Table1 T1 
INNER JOIN Table2 T2 
    ON  T2.something = T1.something 
WHERE  (@parameter1 IS NULL OR T1.Column1 = @parameter1) 
     AND (@parameter2 IS NULL OR T2.Column2 = @parameter2) 
     AND (@parameter3 IS NULL OR T1.Column3 LIKE '%' + @parameter3 + '%') 
     AND (@parameter4 IS NULL OR T2.Column4 LIKE '%' + @parameter4 + '%')  
     AND (@parameter5 IS NULL OR T1.Column5 = @parameter5) 

ten może trwać nawet do 30-40 parametrów i co zauważyliśmy to choćby parameter1 jest plan wykonanie przechodzi skanów indeks inne tabele, które mogą znacznie spowolnić zapytanie (kilka sekund). Testy pokazują, że zachowanie tylko pierwszego wiersza z instrukcji WHERE powoduje natychmiastowe zapytanie.

  1. Czytałem, że shortcuiting nie jest możliwe, ale istnieją sposoby obejścia lub do konstruowania zapytań, które może być bardziej efektywne?

  2. Obecnie pracujemy nad tym problemem, mając różne wersje tego samego SELECT/FROM/JOINS, ale z innym zestawem parametrów w klauzuli WHERE i w zależności od tego, które parametry są przekazywane, wybieramy odpowiednią instrukcję wyboru, którą chcemy przejść. Jest to długi, brudny i trudny do utrzymania.

+3

Czy rozważałeś użycie [dynamicznego SQL] (http://www.sommarskog.se/dynamic_sql.html)? Nawet z zastrzeżeniem [SQL Injection] (http://en.wikipedia.org/wiki/SQL_injection) może być bardziej odpowiedni do twoich potrzeb. – Oded

+0

Budowanie sparametryzowanego dynamicznego sql i sql injection nie jest problemem – StrayCatDBA

+0

Spójrzmy ponownie na dynamiczny sql, ale wydaje się, że po prostu wracamy do tego, jak zwykliśmy robić rzeczy i budować złożone łańcuchy kodu SQL w samych aplikacjach z kilka warunków, które sprawiły, że niemal niemożliwe było szybkie zrozumienie zapytania. Czy istnieje również sposób na utrzymanie podświetlania składni/narzędzi w studiu zarządzania SQL dla tych zapytań? – FrancoisCN

Odpowiedz

4

Plany kwerend w SQL Server są kompilowane i przechowywane do ponownego użycia. Nawet jeśli SQL Server widzi, że twoje parametry są null, musi wymyślić plan zapytań, który będzie działał w przypadkach, w których są one not null.

Wskazówka dotycząca zapytań option (recompile) została wprowadzona w SQL Server 2005, ale dopiero w programie SQL Server 2008 miała ona wpływ na rodzaj zapytania, które tu masz.

Gdy kwerenda jest rekompilowana za każdym razem, gdy nie będzie przechowywana w pamięci podręcznej planu zapytań, tak aby SQL Server mógł zoptymalizować kontrole pod kątem parametrów o wartości null.

Czytaj więcej na ten temat tutaj Dynamic Search Conditions in T-SQL

przykładowy kod można przetestować na, aby zobaczyć różnicę w planach zapytania. Pierwsze wywołanie do SP wykona wyszukiwanie indeksu, a drugie wykona sklonowany indeks.

create table T 
(
    ID int identity primary key, 
    Col1 int, 
    Col2 int 
); 

go 

create index IX_T on T(Col1); 

go 

create procedure GetT 
    @Col1 int, 
    @Col2 int 
as 

select ID 
from T 
where (Col1 = @Col1 or @Col1 is null) and 
     (Col2 = @Col2 or @Col2 is null) 
option (recompile); 

go 

exec GetT 1, null 
exec GetT 1, 1 
+1

Użyłem tego podejścia do wielkiego sukcesu. Jedyne problemy, jakie miałem, to sytuacja, w której liczba kompilacji staje się problemem. Następnie dynamiczne sparametryzowane sql jest jedyną realną opcją. – StrayCatDBA

+0

Co masz na myśli przez liczbę kompilacji staje się problemem? – FrancoisCN

+0

@FrancoisCN Kompilowanie zapytania zajmuje zasoby (CPU) na serwerze i użycie 'opcji (rekompilacja)' oznacza, że ​​zapytanie zostanie skompilowane dla każdego wykonania. Używanie go może więc nadwerężyć twój serwer. Wielkość wpływu zależy od złożoności zapytania i częstotliwości jego wykonywania. –