W tym artykule przyjrzymy się operatorowi „ZASTOSUJ” i jego odmianom – ZASTOSUJ KRZYŻOWY i ZASTOSUJ ZEWNĘTRZNY wraz z przykładami ich użycia.
W szczególności dowiemy się:
- różnica między CROSS APPLY a klauzulą JOIN
- jak połączyć wyniki zapytań SQL z funkcjami oceniającymi tabele
- jak identyfikować problemy z wydajnością, odpytując dynamiczne widoki zarządzania i dynamiczne funkcje zarządzania.
Co to jest klauzula ZASTOSUJ
Firma Microsoft wprowadziła operator APPLY w SQL Server 2005. Operator APPLY jest podobny do klauzuli T-SQL JOIN, ponieważ umożliwia również łączenie dwóch tabel – na przykład można połączyć tabelę zewnętrzną z tabelą wewnętrzną. Operator APPLY jest dobrym rozwiązaniem, gdy po jednej stronie mamy wyrażenie obliczane w tabeli, które chcemy obliczyć dla każdego wiersza z tabeli, którą mamy po drugiej stronie. Tak więc tabela po prawej stronie jest przetwarzana dla każdego wiersza tabeli po lewej stronie. Tabela po lewej stronie jest oceniana jako pierwsza, a następnie tabela po prawej stronie jest oceniana względem każdego wiersza tabeli po lewej stronie w celu wygenerowania końcowego zestawu wyników. Ostateczny zestaw wyników zawiera wszystkie kolumny z obu tabel.
Operator APPLY ma dwie odmiany:
- ZASTOSUJ KRZYŻ
- ZASTOSOWANIE ZEWNĘTRZNE
ZASTOSUJ KRZYŻ
CROSS APPLY jest podobny do INNER JOIN, ale może być również używany do łączenia funkcji oceniających tabele z tabelami SQL. Ostateczny wynik CROSS APPLY składa się z rekordów dopasowanych między wynikiem funkcji oceniającej tabelę a tabelą SQL.
ZASTOSOWANIE ZEWNĘTRZNE
OUTER APPLY przypomina LEFT JOIN, ale ma możliwość łączenia funkcji oceniających tabele z tabelami SQL. Ostateczny wynik OUTER APPLY zawiera wszystkie rekordy z lewej strony tabeli lub funkcji wartościującej tabelę, nawet jeśli nie pasują one do rekordów w prawej tabeli lub funkcji wartościującej tabelę.
Teraz wyjaśnię obie odmiany na przykładach.
Przykłady użycia
Przygotowywanie konfiguracji demonstracyjnej
Aby przygotować konfigurację demonstracyjną, musisz utworzyć tabele o nazwach „Pracownicy” i „Dział” w bazie danych, którą nazwiemy „Baza danych demo”. Aby to zrobić, uruchom następujący kod:
UŻYJ DEMODATABASE GO CREATE TABLE [DBO].[PRACOWNICY] ( [NAZWA PRACOWNIKA] [VARCHAR](MAX) NULL, [DATA URODZIN] [DATETIME] NULL, [STANOWISKO] [VARCHAR](150) NULL, [IDENTYFIKATOR EMAIL] [ VARCHAR](100) NULL, [PHONENUMBER] [VARCHAR](20) NULL, [HIREDATE] [DATETIME] NULL, [DEPARTMENTID] [INT] NULL ) GO CREATE TABLE [DBO].[DZIAŁ] ( [DEPARTMENTID] INT IDENTITY (1, 1), [NAZWA DZIAŁU] [VARCHAR](MAX) NULL) Idź
Następnie wstawiamy fałszywe dane do obu tabel. Poniższy skrypt wstawi dane do „Pracownika s ” tabela:
[rozwiń tytuł =”PEŁNE ZAPYTANIE „]
WSTAW [DBO].[PRACOWNIKÓW] ([NAZWISKO PRACOWNIKA], [DATA URODZIN], [STANOWISKO PRACY], [IDENTYFIKATOR E-MAIL], [NUMER TELEFONU], [DATA ZATRUDNIENIA], [ID DZIAŁU]) WARTOŚCI (N'KEN J SÁNCHEZ', OBSADZKA (N'1969-01-29T00:00:00.000' JAKO DATA GODZINA), N'DYREKTOR GŁÓWNY', N'[email protected]', N'697-555-0142', CAST(N'2009-01- 14T00:00:00.000' JAKO DATETIME), 1), (N'TERRI LEE DUFFY', CAST(N'1971-08-01T00:00:00.000' JAKO DATETIME), N'VICE PREZES INŻYNIERII', N'przykład @sqldat.com', N'819-555-0175', CAST (N'2008-01-31T00:00:00.000' JAKO DATETIME), NULL), (N'ROBERTO TAMBURELLO', CAST (N'1974-11) -12T00:00:00.000' AS DATETIME), N'ENGINEERING MANAGER', N'[email protected]', N'212-555-0187', CAST(N'2007-11-11T00:00:00.000' AS DATETIME), NULL), (N'ROB WALTERS', CAST (N'1974-12-23T00:00:00.000' JAKO DATETIME), N' SENIOR TOOL DESIGNER', N'[email protected]', N'612-555-0100', CAST(N'2007-12-05T00:00:00.000' JAKO DATETIME), NULL), (N'GAIL A ERICKSON ', CAST(N'1952-09-27T00:00:00.000' JAKO DATETIME), N'DESIGN ENGINEER', N'[email protected]', N'849-555-0139', CAST(N'2008- 01-06T00:00:00.000' JAKO DATETIME), NULL), (N'JOSSEF H GOLDBERG', CAST(N'1959-03-11T00:00:00.000' JAKO DATETIME), N'DESIGN ENGINEER', N'przykład @sqldat.com', N'122-555-0189', CAST (N'2008-01-24T00:00:00.000' JAKO DATETIME), NULL), (N'DYLAN A MILLER', CAST (N'1987- 02-24T00:00:00.000' JAKO DATETIME), N'MENEDŻER BADAŃ I ROZWOJU', N'[email protected]', N'181-555-0156', CAST(N'2009-02-08T00:00:00.000' JAKO DATETIME), 3), (N'DIANE L MARGHEIM', CAST(N'1986-06-05T00:00:00.000' JAKO DATETIME), N'INŻYNIER BADAWCZY I ROZWOJU', N'[email protected]', N'815-555-0138', CAST(N'2008-12-29T00:00:00.000' JAKO DATETIME), 3), (N'GIGI N MATTHEW', CAST(N '1979-01-21T00:00:00.000' JAKO DATETIME), N'INŻYNIER BADAWCZY I ROZWOJU', N'[email protected]', N'185-555-0186', CAST(N'2009-01-16T00 :00:00.000' JAKO DATETIME), 3), (N'MICHAEL RAHEEM', CAST(N'1984-11-30T00:00:00.000' JAKO DATETIME), N'MENEDŻER BADAŃ I ROZWOJU', N'example@sqldat .com ', N'330-555-2568', PRZESYŁANIE (N'2009-05-03T00:00:00.000' JAKO DATETIME), 3)
[/rozwiń]
Aby dodać dane do naszego „Działu ”, uruchom następujący skrypt:
WSTAW [DBO].[DZIAŁ] ([ID WYDZIAŁU], [NAZWA WYDZIAŁU]) WARTOŚCI (1, N'IT'), (2, N'TECHNICZNE'), (3, N'BADANIA I ROZWÓJ')
Teraz, aby zweryfikować dane, wykonaj kod widoczny poniżej:
SELECT [NAZWA PRACOWNIKA], [DATA URODZIN], [STANOWISKO], [IDENTYFIKATOR E-MAIL], [NUMER TELEFONU], [DATA ZATRUDNIENIA], [ID DZIAŁU] Z [PRACOWNIKÓW] GOSELECT [ID DZIAŁU], [NAZWA DZIAŁU] Z [DZIAŁU] GO
Oto pożądany wynik:
Tworzenie i testowanie funkcji z wartościami tabelarycznymi
Jak już wspomniałem, „ZASTOSUJ KRZYŻOWY ” i „ZASTOSOWANIE ZEWNĘTRZNE ” służą do łączenia tabel SQL z funkcjami oceniającymi tabele. Aby to zademonstrować, utwórzmy funkcję obliczającą tabelę o nazwie „getEmployeeData ”. Ta funkcja użyje wartości z ID działu kolumna jako parametr wejściowy i zwróć wszystkich pracowników z działu korespondentów.
Aby utworzyć funkcję, uruchom następujący skrypt:
CREATE FUNCTION Getemployeesbydepartment (@DEPARTMENTID INT) ZWRACA @EMPLOYEES TABELA (NAZWA PRACOWNIKA VARCHAR (MAX), DATA URODZENIA DATETIME, JOBTITLE VARCHAR(150), EMAILID VARCHAR (100), NUMER TELEFONU VARCHAR(20), WYNAJMUJ DATE GODZINA, WYJAZD )) NA POCZĄTKU WSTAWIĆ W @EMPLOYEES SELECT A.NAZWISKO PRACOWNIKA, A.DATA URODZIN, A.JOBTITLE, A.EMAILID, A.PHONENUMBER, A.HIREDATE, A.DEPARTMENTID FROM [PRACOWNIKI] A WHERE A.DEPARTMENTID =@DEPARTMENTID RETURN END
Teraz, aby przetestować funkcję, przekażemy „1 ” jako „ID wydziału ” do „Getemployeesbydepartment funkcja. Aby to zrobić, wykonaj poniższy skrypt:
UŻYJ DEMODATABASEGOSELECT NAZWISKO PRACOWNIKA, DATA URODZENIA, NAZWA STANOWISKA, ID E-MAIL, NUMER TELEFONU, DATA ZATRUDNIENIA, ID DZIAŁU OD ZATRUDNIONYCH Z DZIAŁU (1)
Dane wyjściowe powinny wyglądać następująco:
Dołączanie do tabeli za pomocą funkcji oceniającej tabelę za pomocą CROSS APPLY
Spróbujmy teraz dołączyć do stołu Pracownicy z „Getemployeesbydepartment ” funkcja oceniana w tabeli przy użyciu CROSS APPLY . Jak wspomniałem, ZASTOSUJ KRZYŻ operator jest podobny do klauzuli Join. Wypełni wszystkie rekordy od „Pracownika ” tabela, dla której w danych wyjściowych „Getemployeesbydepartment znajdują się pasujące wiersze ”.
Uruchom następujący skrypt:
WYBIERZ A.[NAZWISKO PRACOWNIKA], A.[DATA URODZIN], A.[NAZWA PRACY], A.[IDENTYFIKATOR E-MAIL], A.[NUMER TELEFONU], A.[DATA ZATRUDNIENIA], B.[NAZWA DZIAŁU] Z DZIAŁU B KRZYŻYK ZASTOSUJ ZATRUDNIENIZDZIAŁU(B.DEPARTMENTID) A
Dane wyjściowe powinny wyglądać następująco:
Dołączanie do tabeli z funkcją oceny tabeli za pomocą funkcji OUTER APPLY
Teraz spróbujmy dołączyć do stołu Pracownicy z „Getemployeesbydepartment ” funkcja oceniana w tabeli przy użyciu OUTER APPLY . Jak wspomniałem wcześniej, ZASTOSOWANIE ZEWNĘTRZNE operator przypomina „POŁĄCZENIE ZEWNĘTRZNE ” klauzula. Wypełnia wszystkie rekordy od „Pracownika ” i dane wyjściowe „Getemployeesbydepartment funkcja.
Uruchom następujący skrypt:
WYBIERZ A.[NAZWISKO PRACOWNIKA], A.[DATA URODZIN], A.[NAZWA PRACY], A.[IDENTYFIKATOR E-MAIL], A.[NUMER TELEFONU], A.[DATA ZATRUDNIENIA], B.[NAZWA DZIAŁU] Z DZIAŁU B ZASTOSOWANIE ZEWNĘTRZNE ZATRUDNIENIZDZIAŁU(B.DEPARTMENTID) A
Oto wynik, który powinieneś zobaczyć w wyniku:
Identyfikowanie problemów z wydajnością za pomocą funkcji i widoków dynamicznego zarządzania
Pokażę ci inny przykład. Tutaj zobaczymy, jak uzyskać plan zapytania i odpowiadający mu tekst zapytania, korzystając z funkcji dynamicznego zarządzania i dynamicznych widoków zarządzania.
W celach demonstracyjnych stworzyłem tabelę o nazwie „SmokeTestResults ” w „Bazie DemoData”. Zawiera wyniki testu dymu aplikacyjnego. Wyobraźmy sobie, że przez pomyłkę programista wykonuje zapytanie SQL, aby wypełnić dane z „SmokeTestResults ” bez dodawania filtra, co znacznie zmniejsza wydajność bazy danych.
Jako administrator baz danych musimy zidentyfikować zapytanie wymagające dużej ilości zasobów. Aby to zrobić, użyjemy „sys.dm_exec_requests ” i „sys.dm_exec_sql_text funkcja.
„Sys.dm_exec_requests ” to dynamiczny widok zarządzania, który zawiera następujące ważne szczegóły, których możemy użyć do zidentyfikowania zapytania pochłaniającego zasoby:
- Identyfikator sesji
- Czas procesora
- Typ oczekiwania
- Identyfikator bazy danych
- Odczyty (fizyczne)
- Zapisuje (fizyczne)
- Odczyty logiczne
- Uchwyt SQL
- Obsługa planu
- Stan zapytania
- Polecenie
- Identyfikator transakcji
„sys.dm_exec_sql_text ” to dynamiczna funkcja zarządzania, która akceptuje dojście SQL jako parametr wejściowy i zawiera następujące szczegóły:
- Identyfikator bazy danych
- Identyfikator obiektu
- Jest zaszyfrowany
- Tekst zapytania SQL
Teraz uruchommy następujące zapytanie, aby wygenerować trochę stresu w bazie danych ASAP. Wykonaj następujące zapytanie:
UŻYJ ASAP GO SELECT TSID, USERID, EXECUTIONID, EX_RESULTFILE, EX_TESTDATAFILE, EX_ZIPFILE, EX_STARTTIME, EX_ENDTIME, EX_REMARKS FROM [ASAP].[DBO].[SMOKETESTRESULTS]
SQL Server przydziela identyfikator sesji „66” i rozpoczyna wykonywanie zapytania. Zobacz następujący obraz:
Teraz, aby rozwiązać ten problem, potrzebujemy identyfikatora bazy danych, odczytów logicznych SQL Zapytanie, polecenie, identyfikator sesji, typ oczekiwania iuchwyt SQL . Jak wspomniałem, możemy uzyskać ID bazy danych, odczyty logiczne, polecenie, identyfikator sesji, typ oczekiwania i uchwyt SQL z „sys.dm_exec_requests”. Aby uzyskać zapytanie SQL , musimy użyć „sys.dm_exec_sql_text. ” Jest to funkcja dynamicznego zarządzania, więc trzeba by dołączyć do „sys.dm_exec_requests ” z „sys.dm_exec_sql_text ” za pomocą CROSS APPLY.
W oknie edytora nowych zapytań uruchom następujące zapytanie:
WYBIERZ B.TEKST, A.WAIT_TYPE, A.LAST_WAIT_TYPE, A.COMMAND, A.SESSION_ID, CPU_TIME, A.BLOCKING_SESSION_ID, A.LOGICAL_READS FROM SYS.DM_EXEC_REQUES A CROSS APPLY SYS.DM_EXEC_SQL_TEXANDLEA. /pre>Powinno to dać następujący wynik:
Jak widać na powyższym zrzucie ekranu, zapytanie zwróciło wszystkie informacje wymagane do zidentyfikowania problemu z wydajnością.
Teraz oprócz tekstu zapytania chcemy uzyskać plan wykonania, który został użyty do wykonania zapytania. Aby to zrobić, użyjemy „sys.dm_exec_query_plan” funkcja.
„sys.dm_exec_query_plan ” to dynamiczna funkcja zarządzania, która akceptuje uchwyt planu jako parametr wejściowy i zawiera następujące szczegóły:
- Identyfikator bazy danych
- Identyfikator obiektu
- Jest zaszyfrowany
- Plan zapytań SQL w formacie XML
Aby wypełnić plan wykonania zapytania, musimy użyć CROSS APPLY, aby dołączyć do „sys.dm_exec_requests ” i „sys.dm_exec_query_plan. ”
Otwórz okno edytora nowych zapytań i wykonaj następujące zapytanie:
SELECT B.TEXT, A.WAIT_TYPE, A.LAST_WAIT_TYPE, A.COMMAND, A.SESSION_ID, CPU_TIME, A.BLOCKING_SESSION_ID, A.LOGICAL_READS, C.QUERY_PLAN FROM SYS.DM_EXEC_REQUES A CROSS APPLY SYS_DM_EXEC SQL_HANDLE) B KRZYŻ ZASTOSUJ SYS.DM_EXEC_QUERY_PLAN (A.PLAN_HANDLE) CDane wyjściowe powinny wyglądać następująco:
Teraz, jak widać, plan zapytania jest domyślnie generowany w formacie XML. Aby otworzyć go jako reprezentację graficzną, kliknij wynik XML w query_plan kolumna, jak pokazano na powyższym obrazku. Po kliknięciu wyniku XML plan wykonania zostanie otwarty w nowym oknie, jak pokazano na poniższym obrazku:
Uzyskiwanie listy tabel z wysoce rozdrobnionymi indeksami za pomocą dynamicznych widoków i funkcji zarządzania
Zobaczmy jeszcze jeden przykład. Chcę otrzymać listę tabel z indeksami, które w danej bazie danych mają fragmentację 50% lub większą. Aby pobrać te tabele, będziemy musieli użyć „sys.dm_db_index_physical_stats ” i „sys.tables funkcja.
„Tabele Sys. ” to dynamiczny widok zarządzania, który wypełnia listę tabel w określonej bazie danych.
„sys.dm_db_index_physical_stats ” to dynamiczna funkcja zarządzania, która akceptuje następujące parametry wejściowe:
- Identyfikator bazy danych
- Identyfikator obiektu
- Identyfikator indeksu
- Numer partycji
- Tryb
Zwraca szczegółowe informacje o stanie fizycznym określonego indeksu.
Teraz, aby wypełnić listę pofragmentowanych indeksów, musimy dołączyć do „sys.dm_db_index_physical_stats ” i „sys.tables ” używając CROSS APPLY. Uruchom następujące zapytanie:
SELECT TABLES.NAME, INDEXSTATISTICS.ALLOC_UNIT_TYPE_DESC, CONVERT(NUMERIC(10, 2), INDEXSTATISTICS.AVG_FRAGMENTATION_IN_PERCENT) AS PERCENTAGEFRAGMENTATION, INDEXSTATISTICS.PAGE_COUNT FROM SYS.TABLES AS TABLES_DMOSS_PHOSS APPS TABLES_DMOSS_DB() , NULL, NULL, NULL) JAKO INDEXSTATISTICS GDZIE INDEXSTATISTICS.DATABASE_ID =DB_ID() AND AVG_FRAGMENTATION_IN_PERCENT>=50 ORDER BY INDEXSTATISTICS.AVG_FRAGMENTATION_IN_PERCENT DESCZapytanie powinno dać następujący wynik:
Podsumowanie
W tym artykule omówiliśmy operator APPLY, jego odmiany – CROSS APPLY i OUTER APPLY oraz sposób, w jaki pracujesz. Zobaczyliśmy również, jak można ich używać do identyfikowania problemów z wydajnością SQL za pomocą dynamicznych widoków zarządzania i dynamicznych funkcji zarządzania.