Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

selezionare il degrado delle prestazioni dell'istruzione quando si utilizza DISTINCT con i parametri

Il problema non è che DISTINCT sta causando un degrado delle prestazioni con i parametri, è che il resto della query non viene ottimizzato nella query parametrizzata perché l'ottimizzatore non ottimizzerà solo tutti i join usando [email protected] _ADMINISTRATOR come farà con solo 1=1. Non ottimizzerà i join via senza distinto perché deve restituire duplicati in base al risultato dei join.

Come mai? Perché il piano di esecuzione che elimina tutti i join non sarebbe valido per qualsiasi valore diverso da @IS_ADMINISTRATOR =1. Non genererà mai quel piano indipendentemente dal fatto che tu stia memorizzando nella cache i piani o meno.

Questo funziona così come la query non parametrizzata sul mio server 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

Ciò che è chiaro dal piano di query che vedo eseguendo il tuo esempio è che @IS_ADMINISTRATOR = 1 non viene ottimizzato allo stesso modo di 1=1 . Nel tuo esempio non parametrizzato, i JOINS sono completamente ottimizzati e restituisce solo ogni ID nella tabella DOCUMENTS (molto semplice).

Mancano anche diverse ottimizzazioni quando @IS_ADMINISTRATOR <> 1 . Ad esempio, il LEFT OUTER JOIN Le S vengono automaticamente cambiate in INNER JOIN s senza quel OR clausola, ma vengono lasciati così come sono con quella o una clausola.

Vedi anche questa risposta:SQL LIKE % FOR INTEGERS per un'alternativa SQL dinamica.

Ovviamente, questo non spiega davvero la differenza di prestazioni nella tua domanda originale, dal momento che non hai l'OR lì dentro. Presumo che sia stata una svista.