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

vælg forringelse af udsagns ydeevne, når du bruger DISTINCT med parametre

Problemet er ikke, at DISTINCT forårsager en ydeevneforringelse med parametre, det er, at resten af ​​forespørgslen ikke bliver optimeret væk i den parametriserede forespørgsel, fordi optimeringsværktøjet ikke bare vil optimere alle joins ved hjælp af [email protected] _ADMINISTRATOR kan lide det med kun 1=1. Det vil ikke optimere joins væk uden distinkt, fordi den skal returnere dubletter baseret på resultatet af joinforbindelserne.

Hvorfor? Fordi den eksekveringsplan, der smider alle joinforbindelserne ud, ville være ugyldig for enhver anden værdi end @IS_ADMINISTRATOR =1. Den vil aldrig generere den plan, uanset om du cachelagrer planer eller ej.

Dette fungerer lige så godt som den ikke-parametriserede forespørgsel på min 2008-server:

-- 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

Det, der fremgår tydeligt af forespørgselsplanen, jeg kan se, kører dit eksempel, er, at @IS_ADMINISTRATOR = 1 bliver ikke optimeret på samme måde som 1=1 . I dit ikke-parametriserede eksempel er JOINS fuldstændigt optimeret, og det returnerer bare hvert id i DOCUMENTS-tabellen (meget simpelt).

Der mangler også forskellige optimeringer, når @IS_ADMINISTRATOR <> 1 . For eksempel LEFT OUTER JOIN S ændres automatisk til INNER JOIN s uden at OR klausul, men de efterlades som de er med det eller klausul.

Se også dette svar:SQL LIKE % FOR HELETAL for et dynamisk SQL-alternativ.

Selvfølgelig forklarer dette ikke rigtig forskellen i ydeevnen i dit oprindelige spørgsmål, da du ikke har OR derinde. Jeg går ud fra, at det var en forglemmelse.



  1. Returner kolonneoplysninger for en lagret procedure i SQL Server:sp_sproc_columns

  2. Opdatering af Woocommerce-ordrer programmatisk

  3. EXP() Funktion i Oracle

  4. MySQL indsæt hvor ikke eksisterer / hvis ikke eksisterer