Il problema non è che DISTINCT sta causando un degrado delle prestazioni con i parametri, è che il resto della query non viene ottimizzato nella query parametrizzata perché l'ottimizzatore non ottimizzerà solo tutti i join usando [email protected] _ADMINISTRATOR come farà con solo 1=1. Non ottimizzerà i join via senza distinto perché deve restituire duplicati in base al risultato dei join.
Come mai? Perché il piano di esecuzione che elimina tutti i join non sarebbe valido per qualsiasi valore diverso da @IS_ADMINISTRATOR =1. Non genererà mai quel piano indipendentemente dal fatto che tu stia memorizzando nella cache i piani o meno.
Questo funziona così come la query non parametrizzata sul mio server 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
Ciò che è chiaro dal piano di query che vedo eseguendo il tuo esempio è che @IS_ADMINISTRATOR = 1
non viene ottimizzato allo stesso modo di 1=1
. Nel tuo esempio non parametrizzato, i JOINS sono completamente ottimizzati e restituisce solo ogni ID nella tabella DOCUMENTS (molto semplice).
Mancano anche diverse ottimizzazioni quando @IS_ADMINISTRATOR <> 1
. Ad esempio, il LEFT OUTER JOIN
Le S vengono automaticamente cambiate in INNER JOIN
s senza quel OR
clausola, ma vengono lasciati così come sono con quella o una clausola.
Vedi anche questa risposta:SQL LIKE % FOR INTEGERS per un'alternativa SQL dinamica.
Ovviamente, questo non spiega davvero la differenza di prestazioni nella tua domanda originale, dal momento che non hai l'OR lì dentro. Presumo che sia stata una svista.