Database
 sql >> Datenbank >  >> RDS >> Database

Erweitertes SQL:CROSS APPLY und OUTER APPLY

In diesem Artikel sehen wir uns den „APPLY“-Operator und seine Variationen an – CROSS APPLY und OUTER APPLY, zusammen mit Beispielen, wie sie verwendet werden können.

Insbesondere lernen wir:

  • der Unterschied zwischen CROSS APPLY und der JOIN-Klausel
  • wie man die Ausgabe von SQL-Abfragen mit tabellenausgewerteten Funktionen verbindet
  • Erkennen von Leistungsproblemen durch Abfragen dynamischer Verwaltungsansichten und dynamischer Verwaltungsfunktionen.

Was die APPLY-Klausel ist

Microsoft hat den APPLY-Operator in SQL Server 2005 eingeführt. Der APPLY-Operator ähnelt der T-SQL-JOIN-Klausel, da er Ihnen auch ermöglicht, zwei Tabellen zu verknüpfen – Sie können beispielsweise eine äußere Tabelle mit einer inneren Tabelle verknüpfen. Der APPLY-Operator ist eine gute Option, wenn wir auf der einen Seite einen tabellenausgewerteten Ausdruck haben, den wir für jede Zeile aus der Tabelle auf der anderen Seite auswerten möchten. Somit wird die Tabelle auf der rechten Seite für jede Zeile der Tabelle auf der linken Seite verarbeitet. Die Tabelle auf der linken Seite wird zuerst ausgewertet, und dann wird die Tabelle auf der rechten Seite gegen jede Zeile der Tabelle auf der linken Seite ausgewertet, um die endgültige Ergebnismenge zu generieren. Die endgültige Ergebnismenge enthält alle Spalten aus beiden Tabellen.

Der APPLY-Operator hat zwei Variationen:

  • QUER ANWENDEN
  • ÄUSSERE ANWENDUNG

QUER ANWENDEN

CROSS APPLY ähnelt INNER JOIN, kann aber auch verwendet werden, um tabellenausgewertete Funktionen mit SQL-Tabellen zu verbinden. Die endgültige Ausgabe von CROSS APPLY besteht aus Datensätzen, die zwischen der Ausgabe einer tabellenausgewerteten Funktion und einer SQL-Tabelle übereinstimmen.

ÄUSSERE ANWENDUNG

OUTER APPLY ähnelt LEFT JOIN, kann aber tabellenausgewertete Funktionen mit SQL-Tabellen verbinden. Die endgültige Ausgabe von OUTER APPLY enthält alle Datensätze aus der linken Tabelle oder Tabellenfunktion, auch wenn sie nicht mit den Datensätzen in der rechten Tabelle oder Tabellenfunktion übereinstimmen.

Lassen Sie mich nun beide Varianten anhand von Beispielen erläutern.

Anwendungsbeispiele

Vorbereitung des Demo-Setups

Um ein Demo-Setup vorzubereiten, müssen Sie Tabellen mit den Namen „Employees“ und „Department“ in einer Datenbank erstellen, die wir „DemoDatabase“ nennen. Führen Sie dazu den folgenden Code aus:

USE DEMODATABASE GO CREATE TABLE [DBO].[MITARBEITER] ( [MITARBEITERNAME] [VARCHAR](MAX) NULL, [GEBURTSTAG] [DATETIME] NULL, [JOBTITLE] [VARCHAR](150) NULL, [EMAILID] [ VARCHAR](100) NULL, [PHONENUMBER] [VARCHAR](20) NULL, [HIREDATE] [DATETIME] NULL, [DEPARTMENTID] [INT] NULL ) GO CREATE TABLE [DBO].[DEPARTMENT] ( [DEPARTMENTID] INT IDENTITY (1, 1), [DEPARTMENTNAME] [VARCHAR](MAX) NULL ) GO

Fügen Sie als Nächstes einige Dummy-Daten in beide Tabellen ein. Das folgende Skript fügt Daten in die Datei „Employee s ” Tabelle:

[expand title =”VOLLSTÄNDIGE ABFRAGE „]

INSERT [DBO].[MITARBEITER] ([MITARBEITERNAME], [GEBURTSDATUM], [JOBBEZEICHNUNG], [E-MAIL-ID], [TELEFONNUMMER], [EINSTELLUNG], [ABTEILUNGS-ID]) WERTE (N'KEN J SÁNCHEZ', CAST (N'1969-01-29T00:00:00.000' AS DATETIME), N'CHIEF EXECUTIVE OFFICER', N'[email protected]', N'697-555-0142', CAST(N'2009-01- 14T00:00:00.000' AS DATETIME), 1), (N'TERRI LEE DUFFY', CAST(N'1971-08-01T00:00:00.000' AS DATETIME), N'VICE PRESIDENT OF ENGINEERING', N'example @sqldat.com', N'819-555-0175', CAST(N'2008-01-31T00:00:00.000' AS 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' AS DATETIME), N' SENIOR TOOL DESIGNER', N'[email protected]', N'612-555-0100', CAST(N'2007-12-05T00:00:00.000' AS DATETIME), NULL), (N'GAIL A ERICKSON ', CAST(N'1952-09-27T00:00:00.000' AS DATETIME), N'DESIGN ENGINEER', N'[email protected]', N'849-555-0139', CAST(N'2008- 01-06T00:00:00.000' AS DATETIME), NULL), (N'JOSSEF H GOLDBERG', CAST(N'1959-03-11T00:00:00.000' AS DATETIME), N'DESIGN ENGINEER', N'example @sqldat.com', N'122-555-0189', CAST(N'2008-01-24T00:00:00.000' AS DATETIME), NULL), (N'DYLAN A MILLER', CAST(N'1987- 02-24T00:00:00.000' AS DATETIME), N'RESEARCH AND DEVELOPMENT MANAGER', N'[email protected]', N'181-555-0156', CAST(N'2009-02-08T00:00:00.000' AS DATETIME), 3), (N'DIANE L MARGHEIM', CAST(N'1986-06-05T00:00:00.000' AS DATETIME), N'RESEARCH AND DEVELOPMENT ENGINEER', N'[email protected]', N'815-555-0138', CAST(N'2008-12-29T00:00:00.000' AS DATETIME), 3), (N'GIGI N MATTHEW', CAST(N '1979-01-21T00:00:00.000' AS DATETIME), N'RESEARCH AND DEVELOPMENT ENGINEER', N'[email protected]', N'185-555-0186', CAST(N'2009-01-16T00 :00:00.000' AS DATETIME), 3), (N'MICHAEL RAHEEM', CAST(N'1984-11-30T00:00:00.000' AS DATETIME), N'RESEARCH AND DEVELOPMENT MANAGER', N'example@sqldat .com', N'330-555-2568', CAST(N'2009-05-03T00:00:00.000' AS DATETIME), 3)

[/expandieren]

Um Daten zu unserer „Abteilung hinzuzufügen ”-Tabelle führen Sie das folgende Skript aus:

INSERT [DBO].[ABTEILUNG] ([ABTEILUNGSID], [ABTEILUNGSNAME]) WERTE (1, N'IT'), (2, N'TECHNISCH'), (3, N'FORSCHUNG UND ENTWICKLUNG')

Um die Daten zu überprüfen, führen Sie nun den folgenden Code aus:

WÄHLEN SIE [MITARBEITERNAME], [GEBURTSDATUM], [JOBBEZEICHNUNG], [E-MAIL-ID], [TELEFONNUMMER], [EINSTELLUNG], [ABTEILUNGS-ID] AUS [MITARBEITER] GEHEN AUSWÄHLEN SIE [ABTEILUNGS-ID], [ABTEILUNGSNAME] AUS [ABTEILUNG] GEHEN 

Hier ist die gewünschte Ausgabe:

Erstellen und Testen einer tabellenausgewerteten Funktion

Wie ich bereits erwähnt habe, „CROSS APPLY “ und „ÄUSSERE ANWENDUNG “ werden verwendet, um SQL-Tabellen mit tabellenausgewerteten Funktionen zu verknüpfen. Um dies zu demonstrieren, erstellen wir eine tabellenausgewertete Funktion mit dem Namen „getEmployeeData“. .“ Diese Funktion verwendet einen Wert aus der DepartmentID als Eingabeparameter und geben alle Mitarbeiter aus der entsprechenden Abteilung zurück.

Führen Sie zum Erstellen der Funktion das folgende Skript aus:

CREATE FUNCTION Getemloyeesbydepartment (@DEPARTMENTID INT) RETURNS @EMPLOYEES TABLE (MITARBEITERNAME VARCHAR (MAX), GEBURTSDATUM DATUM, STELLENBEZEICHNUNG VARCHAR(150), EMAILID VARCHAR(100), PHONENUMBER VARCHAR(20), HIREDATE DATETIME, DEPARTMENTID VARCHAR(500 )) AS BEGIN INSERT INTO @EMPLOYEES SELECT A.MITARBEITERNAME, A.GEBURTSDATUM, A.JOBTITEL, A.EMAILID, A.TELEFONNUMMER, A.EINSTELLUNG, A.ABTEILUNGSID VON [MITARBEITERN] A WHERE A.ABTEILUNGSID =@ABTEILUNGSID RETURN END 

Um die Funktion zu testen, übergeben wir nun „1 “ als „Abteilungs-ID ” zu den “MitarbeiternnachAbteilung ” Funktion. Führen Sie dazu das unten bereitgestellte Skript aus:

VERWENDEN SIE DEMODATABASEGOSELECT MITARBEITERNAME, GEBURTSDATUM, STELLENBEZEICHNUNG, E-MAIL-ID, TELEFONNUMMER, EINSTELLDATUM, ABTEILUNGS-IDVON ARBEITNEHMERN NACH ABTEILUNG ERHALTEN (1)

Die Ausgabe sollte wie folgt aussehen:

Verbinden einer Tabelle mit einer tabellenausgewerteten Funktion mit CROSS APPLY

Lassen Sie uns nun versuchen, der Employees-Tabelle mit dem „Getemployeesbydepartment“ beizutreten ” tabellenausgewertete Funktion mit CROSS APPLY . Wie ich bereits erwähnt habe, das CROSS APPLY -Operator ähnelt der Join-Klausel. Es füllt alle Datensätze aus der Datei „Employee “-Tabelle, für die übereinstimmende Zeilen in der Ausgabe von „Getemployeesbydepartment“ vorhanden sind “.

Führen Sie das folgende Skript aus:

SELECT A.[MITARBEITERNAME], A.[GEBURTSDATUM], A.[JOBBEZEICHNUNG], A.[E-MAIL-ID], A.[TELEFONNUMMER], A.[EINGESTELLT], B.[ABTEILUNGSNAME] AUS ABTEILUNG B BEWERBEN GETEMPLOYEESBYDEPARTMENT(B.DEPARTMENTID) A

Die Ausgabe sollte wie folgt aussehen:

Verbinden einer Tabelle mit einer von einer Tabelle ausgewerteten Funktion mit OUTER APPLY

Lassen Sie uns nun versuchen, der Tabelle „Employees“ mit „Getemployeesbydepartment“ beizutreten ” tabellenausgewertete Funktion mit OUTER APPLY . Wie ich bereits erwähnt habe, die ÄUSSERE ANWENDUNG Operator ähnelt dem „OUTER JOIN ” Klausel. Es füllt alle Datensätze aus der Datei „Employee “-Tabelle und die Ausgabe der „Getemployeesbydepartment ”-Funktion.

Führen Sie das folgende Skript aus:

SELECT A.[MITARBEITERNAME], A.[GEBURTSDATUM], A.[JOBBEZEICHNUNG], A.[E-MAIL-ID], A.[TELEFONNUMMER], A.[EINGESTELLT], B.[ABTEILUNGSNAME] AUS ABTEILUNG B BEWERBEN GETEMPLOYEESBYDEPARTMENT(B.DEPARTMENTID) A

Hier ist die Ausgabe, die Sie als Ergebnis sehen sollten:

Identifizieren von Leistungsproblemen durch Verwendung dynamischer Verwaltungsfunktionen und -ansichten

Lassen Sie mich Ihnen ein anderes Beispiel zeigen. Hier erfahren Sie, wie Sie mithilfe dynamischer Verwaltungsfunktionen und dynamischer Verwaltungsansichten einen Abfrageplan und den entsprechenden Abfragetext erhalten.

Zu Demonstrationszwecken habe ich eine Tabelle mit dem Namen „SmokeTestResults“ erstellt “ in der „DemoDatenbank“. Es enthält Ergebnisse eines Anwendungsrauchtests. Stellen wir uns vor, dass ein Entwickler versehentlich eine SQL-Abfrage ausführt, um die Daten aus „SmokeTestResults“ zu füllen ” ohne Hinzufügen eines Filters, was die Datenbankleistung erheblich reduziert.

Als DBA müssen wir die ressourcenintensive Abfrage identifizieren. Dazu verwenden wir die „sys.dm_exec_requests “-Ansicht und die „sys.dm_exec_sql_text ”-Funktion.

Sys.dm_exec_requests ” ist eine dynamische Verwaltungsansicht, die die folgenden wichtigen Details bereitstellt, die wir verwenden können, um die ressourcenintensive Abfrage zu identifizieren:

  1. Sitzungs-ID
  2. CPU-Zeit
  3. Wartetyp
  4. Datenbank-ID
  5. Liest (physisch)
  6. Schreibt (physisch)
  7. Logische Lesevorgänge
  8. SQL-Handle
  9. Plan-Handle
  10. Abfragestatus
  11. Befehl
  12. Transaktions-ID

sys.dm_exec_sql_text “ ist eine dynamische Verwaltungsfunktion, die ein SQL-Handle akzeptiert als Eingabeparameter und liefert die folgenden Details:

  1. Datenbank-ID
  2. Objekt-ID
  3. Ist verschlüsselt
  4. SQL-Abfragetext

Lassen Sie uns nun die folgende Abfrage ausführen, um die ASAP-Datenbank zu belasten. Führen Sie die folgende Abfrage aus:

ASAP VERWENDEN GO SELECT TSID, USERID, EXECUTIONID, EX_RESULTFILE, EX_TESTDATAFILE, EX_ZIPFILE, EX_STARTTIME, EX_ENDTIME, EX_REMARKS FROM [ASAP].[DBO].[SMOKETESTRESULTS]

SQL Server weist eine Sitzungs-ID „66“ zu und startet die Abfrageausführung. Siehe folgendes Bild:

Um das Problem zu beheben, benötigen wir jetzt die Datenbank-ID, logische Lesevorgänge, SQL Abfrage, Befehl, Sitzungs-ID, Wartetyp undSQL-Handle . Wie ich bereits erwähnt habe, können wir Datenbank-ID, logische Lesevorgänge, Befehl, Sitzungs-ID, Wartetyp erhalten undSQL-Handle aus „sys.dm_exec_requests“. Um die SQL-Abfrage zu erhalten , müssen wir „sys.dm_exec_sql_text. verwenden “ Es handelt sich um eine dynamische Verwaltungsfunktion, daher müsste „sys.dm_exec_requests hinzugefügt werden “ mit „sys.dm_exec_sql_text ” mit CROSS APPLY.

Führen Sie im Fenster Neuer Abfrage-Editor die folgende Abfrage aus:

SELECT B.TEXT, 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_REQUESTS A CROSS APPLY SYS.DM_EXEC_SQL_TEXT(A.SQL_HANDLE) B

Es sollte die folgende Ausgabe erzeugen:

Wie Sie im obigen Screenshot sehen können, hat die Abfrage alle Informationen zurückgegeben, die zum Identifizieren des Leistungsproblems erforderlich sind.

Nun möchten wir zusätzlich zum Abfragetext den Ausführungsplan erhalten, der zur Ausführung der betreffenden Abfrage verwendet wurde. Dazu verwenden wir den „sys.dm_exec_query_plan“ Funktion.

sys.dm_exec_query_plan ” ist eine dynamische Verwaltungsfunktion, die ein Plan-Handle akzeptiert als Eingabeparameter und liefert die folgenden Details:

  1. Datenbank-ID
  2. Objekt-ID
  3. Ist verschlüsselt
  4. SQL-Abfrageplan im XML-Format

Um den Abfrageausführungsplan zu füllen, müssen wir CROSS APPLY verwenden, um „sys.dm_exec_requests zu verbinden “ und „sys.dm_exec_query_plan.

Öffnen Sie das Editorfenster Neue Abfrage und führen Sie die folgende Abfrage aus:

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_REQUESTS A CROSS APPLY SYS.DM_EXEC_SQL_TEXT(A. SQL_HANDLE) B CROSS APPLY SYS.DM_EXEC_QUERY_PLAN (A.PLAN_HANDLE) C

Die Ausgabe sollte wie folgt aussehen:

Wie Sie sehen können, wird der Abfrageplan jetzt standardmäßig im XML-Format generiert. Um es als grafische Darstellung zu öffnen, klicken Sie auf die XML-Ausgabe im query_plan Spalte wie im obigen Bild gezeigt. Sobald Sie auf die XML-Ausgabe klicken, wird der Ausführungsplan in einem neuen Fenster geöffnet, wie in der folgenden Abbildung gezeigt:

Erhalten einer Liste von Tabellen mit stark fragmentierten Indizes durch Verwendung dynamischer Verwaltungsansichten und -funktionen

Sehen wir uns ein weiteres Beispiel an. Ich möchte eine Liste von Tabellen mit Indizes erhalten, die eine Fragmentierung von 50 % oder mehr in einer bestimmten Datenbank aufweisen. Um diese Tabellen abzurufen, müssen wir die Datei „sys.dm_db_index_physical_stats verwenden “-Ansicht und die „sys.tables ”-Funktion.

Systemtabellen ” ist eine dynamische Verwaltungsansicht, die eine Liste von Tabellen in der spezifischen Datenbank füllt.

sys.dm_db_index_physical_stats “ ist eine dynamische Verwaltungsfunktion, die die folgenden Eingabeparameter akzeptiert:

  1. Datenbank-ID
  2. Objekt-ID
  3. Index-ID
  4. Partitionsnummer
  5. Modus

Es gibt detaillierte Informationen zum physischen Status des angegebenen Indexes zurück.

Um nun die Liste der fragmentierten Indizes zu füllen, müssen wir „sys.dm_db_index_physical_stats beitreten “ und „sys.tables “ mit CROSS APPLY. Führen Sie die folgende Abfrage aus:

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 CROSS APPLY SYS.DM_DB_INDEX_PHYSICAL_STATS (DB_ID(), TABLES.ID , NULL, NULL, NULL) AS INDEXSTATISTICS WHERE INDEXSTATISTICS.DATABASE_ID =DB_ID() AND AVG_FRAGMENTATION_IN_PERCENT>=50 ORDER BY INDEXSTATISTICS.AVG_FRAGMENTATION_IN_PERCENT DESC

Die Abfrage sollte die folgende Ausgabe erzeugen:

Zusammenfassung

In diesem Artikel haben wir den APPLY-Operator, seine Variationen – CROSS APPLY und OUTER APPLY – und Ihre Funktionsweise behandelt. Wir haben auch gesehen, wie Sie sie verwenden können, um SQL-Leistungsprobleme mit dynamischen Verwaltungsansichten und dynamischen Verwaltungsfunktionen zu identifizieren.