Проблемът не е, че DISTINCT причинява влошаване на производителността с параметри, а че останалата част от заявката не е оптимизирана в параметризираната заявка, защото оптимизаторът няма просто да оптимизира всички съединения, използвайки [email protected] _ADMINISTRATOR като че ли само с 1=1. Няма да оптимизира присъединяванията без различен, защото трябва да върне дубликати въз основа на резултата от обединенията.
Защо? Тъй като планът за изпълнение, изхвърлящ всички съединения, би бил невалиден за всяка стойност, различна от @IS_ADMINISTRATOR =1. Той никога няма да генерира този план, независимо дали кеширате планове или не.
Това работи толкова добре, колкото и непараметризираната заявка на моя сървър 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
Това, което става ясно от плана на заявката, който виждам, изпълнявайки вашия пример, е, че @IS_ADMINISTRATOR = 1
не се оптимизира по същия начин като 1=1
. Във вашия непараметризиран пример JOINS са напълно оптимизирани и просто връща всеки идентификатор в таблицата DOCUMENTS (много просто).
Липсват и различни оптимизации, когато @IS_ADMINISTRATOR <> 1
. Например LEFT OUTER JOIN
S се променят автоматично на INNER JOIN
s без това OR
клауза, но те са оставени такива, каквито са с това или клауза.
Вижте също този отговор:SQL LIKE % ЗА ЦЕЛИ ЧИСЛА за динамична SQL алтернатива.
Разбира се, това всъщност не обяснява разликата в производителността във вашия първоначален въпрос, тъй като нямате OR там. Предполагам, че това е пропуск.