Problemet er ikke, at DISTINCT forårsager en ydeevneforringelse med parametre, det er, at resten af forespørgslen ikke bliver optimeret væk i den parametriserede forespørgsel, fordi optimeringsværktøjet ikke bare vil optimere alle joins ved hjælp af [email protected] _ADMINISTRATOR kan lide det med kun 1=1. Det vil ikke optimere joins væk uden distinkt, fordi den skal returnere dubletter baseret på resultatet af joinforbindelserne.
Hvorfor? Fordi den eksekveringsplan, der smider alle joinforbindelserne ud, ville være ugyldig for enhver anden værdi end @IS_ADMINISTRATOR =1. Den vil aldrig generere den plan, uanset om du cachelagrer planer eller ej.
Dette fungerer lige så godt som den ikke-parametriserede forespørgsel på min 2008-server:
-- 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
Det, der fremgår tydeligt af forespørgselsplanen, jeg kan se, kører dit eksempel, er, at @IS_ADMINISTRATOR = 1
bliver ikke optimeret på samme måde som 1=1
. I dit ikke-parametriserede eksempel er JOINS fuldstændigt optimeret, og det returnerer bare hvert id i DOCUMENTS-tabellen (meget simpelt).
Der mangler også forskellige optimeringer, når @IS_ADMINISTRATOR <> 1
. For eksempel LEFT OUTER JOIN
S ændres automatisk til INNER JOIN
s uden at OR
klausul, men de efterlades som de er med det eller klausul.
Se også dette svar:SQL LIKE % FOR HELETAL for et dynamisk SQL-alternativ.
Selvfølgelig forklarer dette ikke rigtig forskellen i ydeevnen i dit oprindelige spørgsmål, da du ikke har OR derinde. Jeg går ud fra, at det var en forglemmelse.