Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

selecione a degradação do desempenho da declaração ao usar DISTINCT com parâmetros


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.