sql >> Databáze >  >> RDS >> Sqlserver

vyberte snížení výkonu příkazu při použití DISTINCT s parametry

Problém není v tom, že DISTINCT způsobuje snížení výkonu s parametry, ale v tom, že zbytek dotazu není v parametrizovaném dotazu optimalizován, protože optimalizátor neoptimalizuje pouze všechna spojení pomocí [email protected] _ADMINISTRATOR jako to bude s pouhým 1=1. Neoptimalizuje spojení bez odlišné, protože potřebuje vracet duplikáty na základě výsledku spojení.

Proč? Protože plán provádění vyhazující všechna spojení by byl neplatný pro jakoukoli jinou hodnotu než @IS_ADMINISTRATOR =1. Nikdy tento plán nevygeneruje bez ohledu na to, zda plány ukládáte do mezipaměti nebo ne.

To funguje stejně jako neparametrický dotaz na mém serveru 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

Z plánu dotazů, který vidím při spuštění vašeho příkladu, je zřejmé, že @IS_ADMINISTRATOR = 1 nedojde k optimalizaci stejně jako 1=1 . Ve vašem neparametrizovaném příkladu jsou JOINS zcela optimalizovány a pouze vrací každé ID v tabulce DOCUMENTS (velmi jednoduché).

Při @IS_ADMINISTRATOR <> 1 také chybí různé optimalizace . Například LEFT OUTER JOIN S se automaticky změní na INNER JOIN s bez že OR klauzule, ale jsou ponechány tak, jak jsou s to nebo klauzule.

Viz také tato odpověď:SQL LIKE % FOR INTEGERS pro dynamickou alternativu SQL.

To samozřejmě nevysvětluje rozdíl ve výkonu ve vaší původní otázce, protože tam nemáte OR. Předpokládám, že to bylo nedopatření.



  1. YEAR() Příklady v SQL Server (T-SQL)

  2. Dotaz vnořený do squeel

  3. Jak hledat lomítko (\) v MySQL? a proč se escapování (\) nevyžaduje pro kde (=), ale pro Like?

  4. Problém s instalací Ruby on Rails - Jak používat instalaci WAMP MySQL?