Problemet är inte att DISTINCT orsakar en prestandaförsämring med parametrar, det är att resten av frågan inte optimeras bort i den parametriserade frågan eftersom optimeraren inte bara kommer att optimera bort alla kopplingar med [email protected] _ADMINISTRATOR gillar det med bara 1=1. Det kommer inte att optimera sammanfogningarna bort utan distinkt eftersom den behöver returnera dubbletter baserat på resultatet av sammanfogningarna.
Varför? Eftersom exekveringsplanen som kastar bort alla kopplingar skulle vara ogiltigt för något annat värde än @IS_ADMINISTRATOR =1. Den kommer aldrig att generera den planen oavsett om du cachar planer eller inte.
Detta fungerar lika bra som den icke-parametriserade frågan 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 som framgår av frågeplanen som jag ser som kör ditt exempel är att @IS_ADMINISTRATOR = 1
optimeras inte på samma sätt som 1=1
. I ditt icke-parametriserade exempel är JOINS helt optimerade, och det returnerar bara varje ID i DOCUMENTS-tabellen (mycket enkelt).
Det saknas också olika optimeringar när @IS_ADMINISTRATOR <> 1
. Till exempel, LEFT OUTER JOIN
S ändras automatiskt till INNER JOIN
s utan den där OR
sats, men de lämnas som de är med det eller klausul.
Se även detta svar:SQL LIKE % FÖR INTEGERS för ett dynamiskt SQL-alternativ.
Naturligtvis förklarar detta inte riktigt prestandaskillnaden i din ursprungliga fråga, eftersom du inte har OR där inne. Jag antar att det var ett förbiseende.