El problema no es que DISTINCT esté causando una degradación del rendimiento con los parámetros, es que el resto de la consulta no se está optimizando en la consulta parametrizada porque el optimizador no solo optimizará todas las uniones usando [email protected] _ADMINISTRATOR como lo hará con solo 1=1. No optimizará las uniones lejos sin distinto porque necesita devolver duplicados en función del resultado de las uniones.
¿Por qué? Porque el plan de ejecución descartando todas las uniones no sería válido para cualquier valor que no sea @IS_ADMINISTRATOR =1. Nunca generará ese plan, independientemente de si está almacenando planes en caché o no.
Esto funciona tan bien como la consulta no parametrizada en mi servidor 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
Lo que está claro del plan de consulta que veo al ejecutar su ejemplo es que @IS_ADMINISTRATOR = 1
no se optimiza igual que 1=1
. En su ejemplo no parametrizado, los JOINS están completamente optimizados y solo devuelve cada ID en la tabla DOCUMENTOS (muy simple).
También faltan diferentes optimizaciones cuando @IS_ADMINISTRATOR <> 1
. Por ejemplo, LEFT OUTER JOIN
S se cambian automáticamente a INNER JOIN
s sin que OR
cláusula, pero se dejan tal cual con esa o cláusula.
Vea también esta respuesta:SQL LIKE % FOR INTEGERS para una alternativa SQL dinámica.
Por supuesto, esto realmente no explica la diferencia de rendimiento en su pregunta original, ya que no tiene el OR allí. Supongo que fue un descuido.