O problema não é que DISTINCT está causando uma degradação de desempenho com parâmetros, é que o resto da consulta não está sendo otimizada na consulta parametrizada porque o otimizador não apenas otimizará todas as junções usando [email protected] _ADMINISTRATOR como será com apenas 1=1. Não otimizará as junções sem distinto porque precisa retornar duplicatas com base no resultado das junções.
Por quê? Porque o plano de execução descartando todas as junções seria inválido para qualquer valor diferente de @IS_ADMINISTRATOR =1. Ele nunca gerará esse plano, independentemente de você estar armazenando planos em cache ou não.
Isso funciona tão bem quanto a consulta não parametrizada no meu 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
O que está claro no plano de consulta que vejo executando seu exemplo é que
@IS_ADMINISTRATOR = 1
não é otimizado da mesma forma que 1=1
. Em seu exemplo não parametrizado, os JOINS são completamente otimizados e apenas retornam todos os ids da tabela DOCUMENTS (muito simples). Também estão faltando otimizações diferentes quando
@IS_ADMINISTRATOR <> 1
. Por exemplo, o LEFT OUTER JOIN
S são alterados automaticamente para INNER JOIN
s sem que OR
cláusula, mas eles são deixados como estão com aquela ou cláusula. Veja também esta resposta:SQL LIKE % FOR INTEGERS para uma alternativa SQL dinâmica.
Claro, isso realmente não explica a diferença de desempenho em sua pergunta original, já que você não tem o OR lá. Imagino que tenha sido um descuido.