Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

wybierz pogorszenie wydajności instrukcji podczas korzystania z DISTINCT z parametrami

Problem nie polega na tym, że DISTINCT powoduje pogorszenie wydajności z parametrami, ale na to, że reszta zapytania nie jest zoptymalizowana w zapytaniu parametrycznym, ponieważ optymalizator nie zoptymalizuje tylko wszystkich sprzężeń przy użyciu [email protected] _ADMINISTRATOR tak jak to będzie z zaledwie 1=1. Nie zoptymalizuje połączeń bez odrębne, ponieważ musi zwracać duplikaty na podstawie wyników złączeń.

Czemu? Ponieważ plan wykonania odrzucający wszystkie połączenia byłby nieprawidłowy dla dowolnej wartości innej niż @IS_ADMINISTRATOR =1. Nigdy nie wygeneruje tego planu, niezależnie od tego, czy buforujesz plany, czy nie.

Działa to równie dobrze jak niesparametryzowane zapytanie na moim serwerze 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 planu zapytań, który widzę w twoim przykładzie, jasno wynika, że ​​@IS_ADMINISTRATOR = 1 nie jest optymalizowany tak samo jak 1=1 . W twoim niesparametryzowanym przykładzie JOINS są całkowicie zoptymalizowane i po prostu zwracają każdy identyfikator w tabeli DOCUMENTS (bardzo proste).

Brakuje również różnych optymalizacji, gdy @IS_ADMINISTRATOR <> 1 . Na przykład LEFT OUTER JOIN S są automatycznie zmieniane na INNER JOIN jest bez że OR klauzula, ale są pozostawione bez zmian z to lub klauzula.

Zobacz także tę odpowiedź:SQL LIKE % FOR INTEGERS dla dynamicznej alternatywy SQL.

Oczywiście nie wyjaśnia to tak naprawdę różnicy w wydajności w twoim pierwotnym pytaniu, ponieważ nie masz tam OR. Zakładam, że to było przeoczenie.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak połączyć wiele wierszy?

  2. Nieprawidłowy numer parametru, stan SQL S1093 php odbc mssql

  3. Dlaczego nie mogę użyć aliasu w instrukcji DELETE?

  4. Skróć datę do godziny/minuty

  5. Zrozumienie SQL Server zawsze szyfrowane