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

Czy przypisanie parametrów wejściowych procedury składowanej do zmiennych lokalnych pomaga zoptymalizować zapytanie?

Nie będę próbował wyjaśniać wszystkich szczegółów dotyczących wąchania parametrów, ale krótko mówiąc, nie, nie zawsze pomoc (i może przeszkadzać).

Wyobraź sobie tabelę (T) z kluczem podstawowym i indeksowaną kolumną Data (A), w tabeli jest 1000 wierszy, 400 ma taką samą wartość A (powiedzmy dzisiaj 20130122), pozostałe 600 wierszy to następne 600 dni , więc tylko 1 rekord na datę.

To zapytanie:

SELECT *FROM TWHERE A ='20130122'; 

Daje inny plan wykonania, aby:

SELECT *FROM TWHERE A ='20130123'; 

Ponieważ statystyki wskażą, że dla pierwszych 400 z 1000 wierszy zostanie zwróconych, optymalizator powinien rozpoznać, że skanowanie tabeli będzie bardziej wydajne niż wyszukiwanie zakładek, podczas gdy drugie przyniesie tylko 1 wiersz, więc wyszukiwanie zakładek będzie znacznie bardziej wydajny.

Wracając do twojego pytania, jeśli zrobiliśmy z tej procedury:

CREATE PROCEDURE dbo.GetFromT @Param DATEAS SELECT * FROM T WHERE A =@Param 

Następnie uruchom

WYKONAJ dbo.GetFromT '20130122'; --400 wierszy 

Zostanie użyty plan zapytania ze skanowaniem tabeli, jeśli przy pierwszym uruchomieniu użyjesz '20130123' jako parametru, będzie on przechowywać plan wyszukiwania zakładek. Do czasu ponownego opracowania procedury plan pozostanie taki sam. Robisz coś takiego:

CREATE PROCEDURE dbo.GetFromT @Param VARCHAR(5)AS DECLARE @Param2 VARCHAR(5) =@Param; SELECT * FROM T WHERE A =@Param2 

Następnie to jest uruchamiane:

WYKONAJ dbo.GetFromT '20130122'; 

Chociaż procedura jest kompilowana za jednym razem, nie przebiega prawidłowo, więc plan zapytań utworzony przy pierwszej kompilacji nie ma pojęcia, że ​​@Param2 stanie się tym samym co @param, a więc optymalizatorem (bez wiedzy o tym, ile wierszy ma oczekiwać) przyjmie, że zostanie zwrócone 300 (30%), co oznacza, że ​​skanowanie tabeli będzie bardziej wydajne niż wyszukiwanie zakładek. Jeśli uruchomisz tę samą procedurę z parametrem „20130123” jako parametr, uzyskasz ten sam plan (niezależnie od tego, z jakim parametrem został on wywołany po raz pierwszy), ponieważ statystyki nie mogą być użyte dla wartości niekonnwn. Zatem uruchomienie tej procedury dla „20130122” byłoby bardziej wydajne, ale dla wszystkich innych wartości byłoby mniej wydajne niż bez parametrów lokalnych (zakładając, że procedura bez parametrów lokalnych została najpierw wywołana z czymkolwiek innym niż „20130122”)

Niektóre zapytania do zademonstrowania, abyś mógł zobaczyć plany wykonania dla siebie

Utwórz schemat i przykładowe dane

<>UTWÓRZ TABELĘ T (ID INT IDENTITY(1, 1) KLUCZ PODSTAWOWY, A DATA NIEZEROWA, B INT, C INT, D INT, E INT); UTWÓRZ INDEKS NIESKLASTOWANY IX_T NA T (A); WSTAW T (A, B, C, D, E)SELECT TOP 400 CAST('20130122' AS DATE), liczba, 2, 3, 4 FROM Master..spt_values ​​WHERE typ ='P'UNION ALLSELECT TOP 600 DATEADD(DAY, number, CAST('20130122' AS DATE)), liczba, 2, 3, 4 FROM Master..spt_values ​​WHERE Type ='P';GOCREATE PROCEDURE dbo.GetFromT @Param DATEAS SELECT * FROM T WHERE A =@ParamGOCREATE PROCEDURE dbo .GetFromT2 @Param DATY ZADEKLAROWAĆ @Param2 DATA =@Param; WYBIERZ * Z T WHERE A =@Param2GO

Uruchom procedury (pokazując rzeczywisty plan wykonania):

EXECUTE GetFromT '20130122';EXECUTE GetFromT '20130123';EXECUTE GetFromT2 '20130122';EXECUTE GetFromT2 '20130123';GOEXECUTE SP_RECOMPILE GetFromT;EXECUTE SP_RECOMPIUTET'; EXECUTE GetFromT2 '20130123';EXECUTE GetFromT2 '20130122'; 

Zobaczysz, że za pierwszym razem GetFromT jest skompilowany używa skanowania tabeli i zachowuje to po uruchomieniu z parametrem '20130122', GetFromT2 używa również skanowania tabeli i zachowuje plan dla „20130122”.

Po ustawieniu procedur do ponownej kompilacji i ponownym uruchomieniu (zanotuj w innej kolejności), GetFromT używa pętli zakładek i zachowuje plan dla „20130122”, mimo że wcześniej uznano, że skanowanie tabeli jest bardziej odpowiednim planem. GetFromT2 nie ma wpływu na zamówienie i ma taki sam plan jak przed ponownym wypełnieniem.

Podsumowując, zależy to od dystrybucji danych i indeksów, częstotliwości rekompilacji i odrobiny szczęścia, czy procedura skorzysta na użyciu zmiennych lokalnych. Z pewnością nie zawsze pomoc.

Mam nadzieję, że rzuciłem nieco światła na efekt używania parametrów lokalnych, planów wykonania i kompilacji procedur składowanych. Jeśli całkowicie zawiodłem lub przegapiłem kluczową kwestię, znacznie bardziej szczegółowe wyjaśnienie można znaleźć tutaj:

http://www.sommarskog.se/query-plan-mysteries.html



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Konwersja wyników Select do skryptu wstawiania — SQL Server

  2. Jak pogrupować czas według godziny lub 10 minut?

  3. Lista tabel używanych we wszystkich procedurach składowanych z nazwą schematu SP

  4. SQL Server 2008 i porównanie znaków Unicode

  5. Microsoft Access a SQL Server