Problem nie polega na tym, że DISTINCT powoduje pogorszenie wydajności z parametrami, ale na to, że reszta zapytania nie jest zoptymalizowana w zapytaniu parametrycznym, ponieważ optymalizator nie zoptymalizuje tylko wszystkich sprzężeń przy użyciu [email protected] _ADMINISTRATOR tak jak to będzie z zaledwie 1=1. Nie zoptymalizuje połączeń bez odrębne, ponieważ musi zwracać duplikaty na podstawie wyników złączeń.
Czemu? Ponieważ plan wykonania odrzucający wszystkie połączenia byłby nieprawidłowy dla dowolnej wartości innej niż @IS_ADMINISTRATOR =1. Nigdy nie wygeneruje tego planu, niezależnie od tego, czy buforujesz plany, czy nie.
Działa to równie dobrze jak niesparametryzowane zapytanie na moim serwerze 2008:
-- PARAMETRIZED QUERY
declare @IS_ADMINISTRATOR int
declare @User_ID int
set @IS_ADMINISTRATOR = 1 -- 1 for administrator 0 for normal
set @User_ID = 50
IF 1 = @IS_ADMINISTRATOR
BEGIN
SELECT DISTINCT -- PLEASE REMEMBER DISTINCT MAKES THE DIFFERENCE!!!
DOC.DOCUMENT_ID
FROM
DOCUMENTS DOC LEFT OUTER JOIN
FOLDERS FOL ON FOL.FOLDER_ID = DOC.FOLDER_ID LEFT OUTER JOIN
ROLES ROL ON (FOL.FOLDER_ID = ROL.FOLDER_ID)
WHERE
1 = 1
END
ELSE
BEGIN
SELECT DISTINCT -- PLEASE REMEMBER DISTINCT MAKES THE DIFFERENCE!!!
DOC.DOCUMENT_ID
FROM
DOCUMENTS DOC LEFT OUTER JOIN
FOLDERS FOL ON FOL.FOLDER_ID = DOC.FOLDER_ID LEFT OUTER JOIN
ROLES ROL ON (FOL.FOLDER_ID = ROL.FOLDER_ID)
WHERE
ROL.USER_ID = @USER_ID
END
Z planu zapytań, który widzę w twoim przykładzie, jasno wynika, że @IS_ADMINISTRATOR = 1
nie jest optymalizowany tak samo jak 1=1
. W twoim niesparametryzowanym przykładzie JOINS są całkowicie zoptymalizowane i po prostu zwracają każdy identyfikator w tabeli DOCUMENTS (bardzo proste).
Brakuje również różnych optymalizacji, gdy @IS_ADMINISTRATOR <> 1
. Na przykład LEFT OUTER JOIN
S są automatycznie zmieniane na INNER JOIN
jest bez że OR
klauzula, ale są pozostawione bez zmian z to lub klauzula.
Zobacz także tę odpowiedź:SQL LIKE % FOR INTEGERS dla dynamicznej alternatywy SQL.
Oczywiście nie wyjaśnia to tak naprawdę różnicy w wydajności w twoim pierwotnym pytaniu, ponieważ nie masz tam OR. Zakładam, że to było przeoczenie.