Einleitung
Auf dieser Seite werden Details zu Operatoren beschrieben, die in Abfrageausführungsplänen von Spanner verwendet werden. Informationen zum Abrufen eines Ausführungsplans für eine bestimmte Abfrage mit der Google Cloud Console finden Sie unter Wie Abfragen von Spanner ausgeführt werden.
Die Abfragen und Ausführungspläne auf dieser Seite basieren auf dem folgenden Datenbankschema:
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX),
BirthDate DATE,
) PRIMARY KEY(SingerId);
CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName);
CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX),
MarketingBudget INT64,
) PRIMARY KEY(SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE;
CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);
CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget);
CREATE TABLE Songs (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
TrackId INT64 NOT NULL,
SongName STRING(MAX),
Duration INT64,
SongGenre STRING(25),
) PRIMARY KEY(SingerId, AlbumId, TrackId),
INTERLEAVE IN PARENT Albums ON DELETE CASCADE;
CREATE INDEX SongsBySingerAlbumSongNameDesc ON Songs(SingerId, AlbumId, SongName DESC), INTERLEAVE IN Albums;
CREATE INDEX SongsBySongName ON Songs(SongName);
CREATE TABLE Concerts (
VenueId INT64 NOT NULL,
SingerId INT64 NOT NULL,
ConcertDate DATE NOT NULL,
BeginTime TIMESTAMP,
EndTime TIMESTAMP,
TicketPrices ARRAY<INT64>,
) PRIMARY KEY(VenueId, SingerId, ConcertDate);
Sie können die folgenden DML-Anweisungen (Data Manipulation Language) verwenden, um diesen Tabellen Daten hinzuzufügen:
INSERT INTO Singers (SingerId, FirstName, LastName, BirthDate)
VALUES (1, "Marc", "Richards", "1970-09-03"),
(2, "Catalina", "Smith", "1990-08-17"),
(3, "Alice", "Trentor", "1991-10-02"),
(4, "Lea", "Martin", "1991-11-09"),
(5, "David", "Lomond", "1977-01-29");
INSERT INTO Albums (SingerId, AlbumId, AlbumTitle)
VALUES (1, 1, "Total Junk"),
(1, 2, "Go, Go, Go"),
(2, 1, "Green"),
(2, 2, "Forever Hold Your Peace"),
(2, 3, "Terrified"),
(3, 1, "Nothing To Do With Me"),
(4, 1, "Play");
INSERT INTO Songs (SingerId, AlbumId, TrackId, SongName, Duration, SongGenre)
VALUES (2, 1, 1, "Let's Get Back Together", 182, "COUNTRY"),
(2, 1, 2, "Starting Again", 156, "ROCK"),
(2, 1, 3, "I Knew You Were Magic", 294, "BLUES"),
(2, 1, 4, "42", 185, "CLASSICAL"),
(2, 1, 5, "Blue", 238, "BLUES"),
(2, 1, 6, "Nothing Is The Same", 303, "BLUES"),
(2, 1, 7, "The Second Time", 255, "ROCK"),
(2, 3, 1, "Fight Story", 194, "ROCK"),
(3, 1, 1, "Not About The Guitar", 278, "BLUES");
Blattoperatoren
Ein Blattoperator ist ein Operator, der keine untergeordneten Elemente hat. Diese Arten von Blattoperatoren gibt es:
Array Unnest
Der Operator Array Unnest vereinfacht ein Eingabe-Array so, dass es in Zeilen von Elementen vorliegt. Jede resultierende Zeile enthält bis zu zwei Spalten: den tatsächlichen Wert aus dem Array und optional die nullbasierte Position im Array.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT a, b FROM UNNEST([1,2,3]) a WITH OFFSET b;
Wird das Array [1,2,3]
in Spalte a
vereinfacht und die Arrayposition in Spalte b
angezeigt.
Das sind die Ergebnisse:
a | b |
---|---|
1 | 0 |
2 | 1 |
3 | 2 |
Das ist der Ausführungsplan:
Generate Relation
Der Operator Generate Relation gibt null oder mehr Zeilen zurück.
Unit Relation
Unit Relation gibt eine Zeile zurück. Das ist ein Sonderfall des Operators Generate Relation.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT 1 + 2 AS Result;
Lautet das Ergebnis:
Result |
---|
3 |
Das ist der Ausführungsplan:
Empty Relation
Empty Relation gibt keine Zeilen zurück. Das ist ein Sonderfall des Operators Generate Relation.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT * FROM Albums LIMIT 0
Lautet das Ergebnis:
No results
Das ist der Ausführungsplan:
Scan
Der Operator Scan gibt Zeilen zurück, indem eine Zeilenquelle gescannt wird. Dies sind die Arten von Scan-Operatoren:
- Table Scan: Es wird eine Tabelle gescannt.
- Index Scan: Es wird ein Index gescannt.
- Batch Scan: Es werden Zwischentabellen gescannt, die von anderen relationalen Operatoren erstellt wurden (z. B. eine Tabelle, die mit Distributed Cross Apply erstellt wurde).
Wann immer möglich wendet Spanner im Rahmen eines Scans einfache Prädikate auf Schlüssel an. Scans werden effizienter ausgeführt, wenn Prädikate angewendet werden, da der Scan nicht die gesamte Tabelle oder den gesamten Index lesen muss. Prädikate werden im Ausführungsplan im Format KeyPredicate: column=value
angezeigt.
Im schlimmsten Fall muss eine Abfrage möglicherweise alle Zeilen in einer Tabelle nachschlagen. Dies führt zu einem vollständigen Scan und wird im Ausführungsplan als full scan: true
angezeigt.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT s.LastName
FROM singers@{FORCE_INDEX=SingersByFirstLastName} AS s
WHERE s.FirstName = 'Catalina';
Das sind die Ergebnisse:
LastName |
---|
Smith |
Das ist der Ausführungsplan:
Im Ausführungsplan sendet der übergeordnete Operator Distributed Union Teilpläne an Remoteserver. Jeder Teilplan hat den Operator Serialize Result und den Operator "Index Scan". Das Prädikat Key Predicate: FirstName = 'Catalina'
schränkt den Scan auf Zeilen im Index SingersByFirstLastname
ein, die als FirstName
den Wert Catalina
haben.
Die Ausgabe von Index Scan wird an den Operator "Serialize Result" zurückgegeben.
Unäre Operatoren
Ein unärer Operator hat nur ein einziges untergeordnetes relationales Element.
Diese unären Operatoren gibt es:
- Aggregate
- Apply Mutations
- Create Batch
- Computing
- Compute Struct
- Filter
- Filter Scan
- Limit
- Zufalls-ID-Zuweisung
- Serialize Result
- Sort
- TVF
- Union Input
Aggregate
Der Operator Aggregate implementiert SQL-Anweisungen vom Typ GROUP BY
und Aggregatfunktionen (z. B. COUNT
). Eingaben für den Operator "Aggregate" werden logisch in Gruppen unterteilt, die in Schlüsselspalten angeordnet sind oder in einer einzigen Gruppe ausgegeben werden, wenn GROUP BY
nicht vorhanden ist. Für jede Gruppe werden null oder mehr Zusammenfassungen berechnet.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT s.SingerId, AVG(s.duration) AS average, COUNT(*) AS count
FROM Songs AS s
GROUP BY SingerId;
Wird die Abfrage nach SingerId
gruppiert und eine AVG
-Zusammenfassung sowie eine COUNT
-Zusammenfassung durchgeführt.
Das sind die Ergebnisse:
SingerId | Durchschnitt | Anzahl |
---|---|---|
3 | 278 | 1 |
2 | 225,875 | 8 |
Das ist der Ausführungsplan:
Mit dem Operator "Aggregate" können streambasierte oder hashbasierte Zusammenfassungen erstellt werden. Der obige Ausführungsplan stellt eine streambasierte Zusammenfassung dar. Streambasierte Zusammenfassungen lesen bereits vorsortierte Eingaben aus (wenn GROUP BY
vorhanden ist) und berechnen die Gruppen ohne Blockierung. Hashbasierte Zusammenfassungen erstellen Hashtabellen, um inkrementelle Zusammenfassungen mehrerer Eingabezeilen gleichzeitig bereitzuhalten. Streambasierte Zusammenfassungen sind schneller und benötigen weniger Speicher als hashbasierte Zusammenfassungen. Die Eingabe muss jedoch nach Schlüsselspalten oder sekundären Indexen sortiert sein.
Bei verteilten Szenarien kann der Operator "Aggregate" in ein lokales/globales Paar aufgeteilt werden. Jeder Remoteserver führt eine lokale Zusammenfassung seiner Eingabezeile durch und gibt dann seine Ergebnisse an den Stammserver zurück. Der Stammserver führt die globale Zusammenfassung durch.
Apply Mutations
Der Operator Apply Mutations wendet die Mutationen aus einer DML-Anweisung auf die Tabelle an. Es ist der oberste Operator in einem Abfrageplan für eine DML-Anweisung.
Wenn Sie zum Beispiel diese Abfrage verwenden:
DELETE FROM Singers
WHERE FirstName = 'Alice';
Das sind die Ergebnisse:
4 rows deleted
This statement deleted 4 rows and did not return any rows.
Das ist der Ausführungsplan:
Create Batch
Der Operator Create Batch erstellt eine Batchsequenz seiner Eingabezeilen. Der Operator "Create Batch" wird normalerweise im Rahmen der Operation Distributed Cross Apply ausgeführt. Die Eingabezeilen können bei der Batchverarbeitung neu geordnet werden. Die Anzahl der Eingabezeilen, die bei der jeweiligen Ausführung des Batch-Operators zu einem Batch zusammengefasst werden, ist variabel.
Beim Operator Distributed Cross Apply finden Sie ein Beispiel für den Operator "Create Batch" in einem Ausführungsplan.
Compute
Der Operator Compute erzeugt eine Ausgabe, indem er die Eingabezeilen ausliest und eine oder mehrere zusätzliche Spalten hinzufügt, die über skalare Ausdrücke berechnet werden. Beim Operator Union All finden Sie ein Beispiel des Operators "Compute" in einem Ausführungsplan.
Compute Struct
Der Operator Compute Struct erstellt eine Variable für eine Struktur, die Felder für alle Eingabespalten enthält.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT FirstName,
ARRAY(SELECT AS STRUCT song.SongName, song.SongGenre
FROM Songs AS song
WHERE song.SingerId = singer.SingerId)
FROM singers AS singer
WHERE singer.SingerId = 3;
Das sind die Ergebnisse:
FirstName | Ohne Angabe |
---|---|
Alice | [["Not About The Guitar","BLUES"]] |
Das ist der Ausführungsplan:
Im Ausführungsplan erhält der Operator "Array Subquery" eine Eingabe vom Operator Distributed Union, der die Eingabe vom Operator "Compute Struct" empfängt. Der Operator "Compute Struct" erstellt eine Struktur aus den Spalten SongName
und SongGenre
der Tabelle Songs
.
Filter
Der Operator Filter liest alle Zeilen der Eingabe aus, wendet ein skalares Prädikat auf jede Zeile an und gibt dann nur die Zeilen zurück, die das Prädikat erfüllen.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT s.LastName FROM (SELECT s.LastName
FROM Singers AS s LIMIT 3) s
WHERE s.LastName LIKE 'Rich%';
Das sind die Ergebnisse:
LastName |
---|
Richards |
Das ist der Ausführungsplan:
Das Prädikat für Interpreten, deren Nachname mit Rich
beginnt, wird als Filter implementiert. Die Eingabedaten des Filters sind die Ausgabedaten eines Indexscans. Die Ausgabedaten des Filters sind die Zeilen, bei denen LastName
mit Rich
beginnt.
Was die Leistung angeht, beeinflusst ein Filter direkt oberhalb von Scan die Geschwindigkeit, mit der Daten gelesen werden. Betrachten Sie zum Beispiel eine Tabelle mit dem Schlüssel k
.
Ein Filter mit dem Prädikat k = 5
direkt oberhalb eines Tabellenscans sucht nach Zeilen, die k = 5
entsprechen, ohne die gesamte Eingabe zu lesen. Das führt zu einer effizienteren Ausführung der Abfrage. Im obigen Beispiel liest der Operator "Filter" nur die Zeilen aus, für die das Prädikat WHERE s.LastName LIKE 'Rich%'
erfüllt ist.
Filter Scan
Der Operator Filter Scan bildet immer die Basis einer Tabellen- oder Indexsuche. Gemeinsam mit dem Scan reduziert er die Anzahl der aus der Datenbank gelesenen Zeilen. Der resultierende Scan erfolgt normalerweise schneller als unter Verwendung eines Filters. Spanner wendet den Filterscan unter bestimmten Bedingungen an:
- Suchbare Bedingung: Die suchbare Bedingung gilt, wenn Spanner Folgendes tun kann:
um eine bestimmte Zeile in der Tabelle festzulegen. Im Allgemeinen geschieht das, wenn sich der Filter in einem Präfix des Primärschlüssels befindet. Wenn der Primärschlüssel beispielsweise aus
Col1
undCol2
besteht, dann ist die KlauselWHERE
, die explizite Werte fürCol1
oderCol1
undCol2
enthält, suchbar. In diesem Fall Spanner liest nur Daten innerhalb des Schlüsselbereichs. - Residualbedingung: Jede andere Bedingung, bei der Spanner die um die gelesene Datenmenge zu begrenzen.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT LastName
FROM Singers
WHERE SingerId = 1
Das sind die Ergebnisse:
LastName |
---|
Richards |
Das ist der Ausführungsplan:
Limit
Der Operator Limit beschränkt die Anzahl der zurückgegebenen Zeilen. Ein optionaler Parameter OFFSET
gibt die erste Zeile an, die zurückgegeben werden soll. Bei verteilten Szenarien kann der Operator "Limit" in ein lokales/globales Paar aufgeteilt werden. Jeder Remoteserver führt eine lokale Begrenzung seiner Eingabezeilen durch und gibt dann seine Ergebnisse an den Stammserver zurück. Der Stammserver fasst die von den Remoteservern gesendeten Zeilen zusammen und wendet dann das globale Limit an.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT s.SongName
FROM Songs AS s
LIMIT 3;
Das sind die Ergebnisse:
SongName |
---|
Not About The Guitar |
The Second Time |
Starting Again |
Das ist der Ausführungsplan:
Das lokale Limit gilt jeweils für die Remoteserver. Der Stammserver fasst die Zeilen von den Remoteservern zusammen und wendet dann das globale Limit an.
Random Id Assign
Der Operator Random Id Assign generiert eine Ausgabe. Dazu liest er seine Eingabezeilen und fügt jeder Zeile eine Zufallszahl hinzu. Es funktioniert mit dem Operator Filter
oder Sort
, um Stichprobenmethoden zu erhalten. Die unterstützten Stichprobenverfahren sind Bernoulli und Reservoir.
Die folgende Abfrage verwendet zum Beispiel die Bernoulli-Stichprobenmethode mit einer Abtastrate von 10 %.
SELECT s.SongName
FROM Songs AS s TABLESAMPLE BERNOULLI (10 PERCENT);
Dies sind die Ergebnisse:
SongName |
---|
Starting Again |
Nothing Is The Same |
Beachten Sie, dass das Ergebnis bei jeder Ausführung variieren kann, obwohl die Abfrage dieselbe ist. Dies liegt daran, dass es sich bei dem Ergebnis um eine Stichprobe handelt.
Dies ist der Ausführungsplan:
In diesem Ausführungsplan erhält der Operator Random Id Assign
seine Eingabe vom Operator Distributed Union, der seine Eingabe von einer Indexsuche empfängt. Der Operator gibt die Zeilen mit zufälligen IDs zurück und der Operator Filter
wendet dann ein Skalarprädikat für die Zufalls-IDs an und gibt etwa 10 % der Zeilen zurück.
Im folgenden Beispiel wird eine Reservoir-Stichprobenerfassung mit einer Stichprobenrate von zwei Zeilen verwendet.
SELECT s.SongName
FROM Songs AS s TABLESAMPLE RESERVOIR (2 ROWS);
Dies sind die Ergebnisse:
SongName |
---|
I Knew You Were Magic |
The Second Time |
Beachten Sie, dass das Ergebnis bei jeder Ausführung variieren kann, obwohl die Abfrage dieselbe ist. Dies liegt daran, dass es sich bei dem Ergebnis um eine Stichprobe handelt.
Dies ist der Ausführungsplan:
In diesem Ausführungsplan erhält der Operator Random Id Assign
seine Eingabe vom Operator Distributed Union, der seine Eingabe von einer Indexsuche empfängt. Der Operator gibt die Zeilen mit zufälligen IDs zurück und der Operator Sort
wendet dann die Sortierreihenfolge auf die zufälligen IDs an und wendet LIMIT
mit zwei Zeilen an.
Serialize Result
Der Operator Serialize Result ist ein Spezialfall des Operators "Compute Struct", der jede Zeile des Endergebnisses der Abfrage serialisiert, um sie an den Client zurückzugeben.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT ARRAY(SELECT AS STRUCT so.SongName, so.SongGenre
FROM Songs AS so
WHERE so.SingerId = s.SingerId)
FROM Singers AS s;
fordert die Abfrage ein Array von SongName
und SongGenre
basierend auf SingerId
an.
Das sind die Ergebnisse:
Ohne Angabe |
---|
[] |
[[Let's Get Back Together, COUNTRY], [Starting Again, ROCK]] |
[[Not About The Guitar, BLUES]] |
[] |
[] |
Das ist der Ausführungsplan:
Der Operator "Serialize Result" erzeugt ein Ergebnis, das für jede Zeile der Tabelle Singers
ein Array von SongName
- und SongGenre
-Paaren für die Lieder des Sängers enthält.
Sort
Der Operator Sort liest die Eingabezeilen aus, sortiert sie nach Spalten und gibt dann die sortierten Ergebnisse zurück.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT s.SongGenre
FROM Songs AS s
ORDER By SongGenre;
Das sind die Ergebnisse:
SongGenre |
---|
BLUES |
BLUES |
BLUES |
BLUES |
KLASSIK |
Land |
ROCK |
ROCK |
ROCK |
Das ist der Ausführungsplan:
In diesem Ausführungsplan erhält der Operator "Sort" die Eingabezeilen vom Operator Distributed Union, sortiert die Eingabezeilen und gibt die sortierten Zeilen an den Operator Serialize Result zurück.
Um die Anzahl der zurückgegebenen Zeilen zu beschränken, kann der Operator "Sort" optional die Parameter LIMIT
und OFFSET
haben. Bei verteilten Szenarien wird der Operator "Sort" mit dem Operator LIMIT
und/oder OFFSET
in ein lokales/globales Paar aufgeteilt. Jeder Remoteserver führt die Sortierung der Eingabezeilen mit der Begrenzung und dem Startwert lokal durch und gibt dann seine Ergebnisse an den Stammserver zurück. Der Stammserver fasst die von den Remoteservern gesendeten Zeilen zusammen, sortiert sie und wendet dann global die Operatoren "Limit" und "Offset" an.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT s.SongGenre
FROM Songs AS s
ORDER By SongGenre
LIMIT 3;
Das sind die Ergebnisse:
SongGenre |
---|
BLUES |
BLUES |
BLUES |
Das ist der Ausführungsplan:
Im Ausführungsplan wird das lokale Limit für die Remoteserver und das globale Limit für den Stammserver aufgeführt.
TVF
Der Operator Tabellenwertfunktion generiert eine Ausgabe. Dazu liest er seine Eingabezeilen und wendet die angegebene Funktion an. Die Funktion kann eine Zuordnung implementieren und dieselbe Anzahl von Zeilen wie die Eingabe zurückgeben. Es kann auch ein Generator sein, der mehr Zeilen oder einen Filter, der weniger Zeilen zurückgibt.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT Genre, SongName
FROM ML.PREDICT(MODEL GenreClassifier, Table Songs)
Das sind die Ergebnisse:
Genre | SongName |
---|---|
Land | Not About The Guitar |
Rock | The Second Time |
Pop | Starting Again |
Pop | Nothing Is The Same |
Land | Let's Get Back Together |
Pop | I Knew You Were Magic |
Elektronische Musik | Blau |
Stein | 42 |
Rock | Fight Story |
Dies ist der Ausführungsplan:
Union Input
Der Operator Union Input gibt Ergebnisse an den Operator Union All zurück. Beim Operator Union All finden Sie ein Beispiel des Operators "Union Input" in einem Ausführungsplan.
Binäre Operatoren
Ein binärer Operator hat zwei untergeordnete relationale Elemente. Diese binären Operatoren gibt es:
Cross Apply
Mit dem Operator "Cross Apply" wird eine Suchanfrage ausgeführt, mit der jede Zeile einer Tabelle abgerufen wird, die zuvor mit einer Suchanfrage aus einer anderen Tabelle abgerufen wurde. Anschließend wird die Schnittmenge der Suchdurchläufe durch alle Tabellen zurückgegeben. Im Gegensatz zu Operatoren mit datensatzbasierter Verarbeitung wie Hash Join führen die Operatoren "Cross Apply" und Outer Apply eine zeilenorientierte Verarbeitung durch. Der Operator "Cross Apply" erhält zwei Eingaben, Input und Map. Der Operator "Cross Apply" wendet jede von der Input-Seite erhaltene Zeile auf die von der Map-Seite erhaltenen Zeilen an. Das Ergebnis von Cross Apply enthält Spalten sowohl von Input als auch von Map.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT si.FirstName,
(SELECT so.SongName
FROM Songs AS so
WHERE so.SingerId=si.SingerId
LIMIT 1)
FROM Singers AS si;
Verlangt die Abfrage den Vornamen eines jeden Interpreten, zusammen mit dem Namen nur eines Titels des Interpreten.
Das sind die Ergebnisse:
FirstName | Ohne Angabe |
---|---|
Alice | Not About The Guitar |
Catalina | Let's Get Back Together |
David | NULL |
Lea | NULL |
Marc | NULL |
Die erste Spalte wird mit Werten aus der Tabelle Singers
und die zweite mit Werten aus der Tabelle Songs
ausgefüllt. In den Fällen, in denen eine SingerId
in der Tabelle Singers
vorhanden war, aber keine übereinstimmende SingerId
in der Tabelle Songs
gefunden werden konnte, enthält die zweite Spalte NULL
.
Das ist der Ausführungsplan:
Der übergeordnete Knoten ist der Operator Distributed Union. Der Operator "Distributed" Union verteilt Teilpläne an Remoteserver. Der Teilplan enthält den Operator Serialize Result, der den Vornamen des Interpreten und den Namen eines Titels des Interpreten berechnet und jede Ausgabezeile serialisiert.
Der Operator "Serialize Result" erhält seine Eingabe vom Operator "Cross Apply".
Die Eingabeseite für den Operator "Cross Apply" stammt aus einem Scan der Tabelle Singers
.
Die Eingabedaten unter Map für den Operator "Cross Apply" enthalten (von oben nach unten):
- Den Operator Aggregate, der
Songs.SongName
zurückgibt - den Operator "Limit", der die Anzahl der zurückgegebenen Titel je Interpret begrenzt
- Einen Indexscan des Index
SongsBySingerAlbumSongNameDesc
Der Operator "Cross Apply" ordnet jede von Input erhaltene Zeile den von Map erhaltenen Zeilen mit derselben SingerId
zu. Die Ausgabe des Operators "Cross Apply" setzt sich aus dem Wert FirstName
aus der Eingabezeile von Input und dem Wert SongName
aus der Eingabezeile von Map zusammen.
Der Wert SongName
lautet NULL
, wenn es unter Map keine Zeile gibt, die der SingerId
entspricht. Der im Ausführungsplan übergeordnete Operator "Distributed Union" fasst dann alle Ausgabezeilen von den Remoteservern zusammen und gibt sie als Abfrageergebnisse zurück.
Hash Join
Der Operator Hash Join ist eine hashbasierte Implementierung von SQL-Join. Hash Joins führen eine setbasierte Verarbeitung aus. Der Operator "Hash Join" liest die als Build markierten Eingabezeilen aus und fügt sie basierend auf einer Join-Bedingung in eine Hashtabelle ein. Der Operator "Hash Join" liest dann die als Probe markierten Eingabezeilen aus. Für jede Zeile, die der Operator "Hash Join" aus der "Probe"-Eingabe ausliest, sucht er nach übereinstimmenden Zeilen in der Hash-Tabelle. Der Operator "Hash Join" gibt die übereinstimmenden Zeilen als Ergebnis zurück.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT a.AlbumTitle, s.SongName
FROM Albums AS a JOIN@{join_method=hash_join} Songs AS s
ON a.SingerId = s.SingerId AND a.AlbumId = s.AlbumId;
Das sind die Ergebnisse:
AlbumTitle | SongName |
---|---|
Nothing To Do With Me | Not About The Guitar |
Green | The Second Time |
Green | Starting Again |
Green | Nothing Is The Same |
Green | Let's Get Back Together |
Green | I Knew You Were Magic |
Green | Blue |
Green | 42 |
Terrified | Fight Story |
Das ist der Ausführungsplan:
Im Ausführungsplan ist Build ein Operator des Typs Distributed Union, der Scans auf die Tabelle Albums
verteilt. Probe ist ein Operator des Typs Distributed Union, der Scans auf dem Index SongsBySingerAlbumSongNameDesc
verteilt.
Der Operator „Hash Join” liest alle Zeilen unter „Build” aus. Jede „Build”-Zeile wird basierend auf den Spalten der Bedingung a.SingerId =
s.SingerId AND a.AlbumId = s.AlbumId
in einer Hashtabelle abgelegt. Als Nächstes liest der Operator „Hash Join” alle Zeilen unter „Probe” aus. Der Operator „Hash Join” sucht für jede „Probe”-Zeile nach Übereinstimmungen mit der Hashtabelle. Die resultierenden Übereinstimmungen werden vom Operator „Hash Join” zurückgegeben.
Resultierende Übereinstimmungen in der Hashtabelle können auch durch eine Residualbedingung gefiltert werden, bevor sie zurückgegeben werden. Ein Beispiel für Residualbedingungen sind Non-Equality Joins. Hash Join-Ausführungspläne können aufgrund von Speicherverwaltung und Join-Varianten komplex sein. Der Hauptalgorithmus eines Hash Join ist auf die Verarbeitung von Inner-, Semi-, Anti- und Outer Join-Varianten ausgelegt.
Merge join
Der Operator Merge Join ist eine zusammengeführte Implementierung des SQL Join. Beide Seiten des Joins erzeugen Zeilen, die nach den Spalten sortiert sind, die in der Join-Bedingung verwendet werden. Der Merge Join verarbeitet beide Eingabestreams gleichzeitig und gibt Zeilen aus, wenn die Join-Bedingung erfüllt ist. Wenn die Eingaben nicht ursprünglich nach Bedarf sortiert sind, fügt das Optimierungstool dem Plan explizite Sort
-Operatoren hinzu.
Merge Join wird vom Optimierungstool nicht automatisch ausgewählt. Um diesen Operator zu verwenden, setzen Sie die Join-Methode im Abfragehinweis auf MERGE_JOIN
, wie im folgenden Beispiel gezeigt:
SELECT a.AlbumTitle, s.SongName
FROM Albums AS a JOIN@{join_method=merge_join} Songs AS s
ON a.SingerId = s.SingerId AND a.AlbumId = s.AlbumId;
Dies sind die Ergebnisse:
AlbumTitle | SongName |
---|---|
Grün | The Second Time |
Green | Starting Again |
Green | Nothing Is The Same |
Green | Let's Get Back Together |
Green | I Knew You Were Magic |
Green | Blue |
Green | 42 |
Terrified | Fight Story |
Nothing To Do With Me | Not About The Guitar |
Dies ist der Ausführungsplan:
In diesem Ausführungsplan wird der Merge Join verteilt, sodass der Join an der Stelle ausgeführt wird, an der sich die Daten befinden. Dadurch kann der Merge Join in diesem Beispiel ohne die Einführung zusätzlicher Sortieroperatoren ausgeführt werden, da beide Tabellenscans bereits nach SingerId
, AlbumId
, der Join-Funktion-Bedingung, sortiert sind. In diesem Plan wird die linke Seite der Tabelle Albums
immer dann gescannt, wenn deren SingerId
, AlbumId
vergleichsweise kleiner ist als die rechte Seite des Index-Scans SongsBySingerAlbumSongNameDesc
, Paar SingerId_1
, AlbumId_1
.
Ebenso wird die rechte Seite fortgesetzt, wenn sie kleiner als die linke Seite ist. Bei dieser Zusammenführung wird weiterhin nach Äquivalenzen gesucht, sodass mögliche Ergebnisse zurückgegeben werden können.
Betrachten Sie ein weiteres Beispiel für einen Merge Join mit der folgenden Abfrage:
SELECT a.AlbumTitle, s.SongName
FROM Albums AS a JOIN@{join_method=merge_join} Songs AS s
ON a.AlbumId = s.AlbumId;
Dies liefert die folgenden Ergebnisse:
AlbumTitle | SongName |
---|---|
Total Junk | The Second Time |
Total Junk | Starting Again |
Total Junk | Nothing Is The Same |
Total Junk | Let\'s Get Back Together |
Total Junk | I Knew You Were Magic |
Total Junk | Blau |
Total Junk | 42 |
Total Junk | Not About The Guitar |
Green | The Second Time |
Green | Starting Again |
Green | Nothing Is The Same |
Green | Let\'s Get Back Together |
Green | I Knew You Were Magic |
Green | Blue |
Green | 42 |
Grün | Not About The Guitar |
Nothing To Do With Me | The Second Time |
Nothing To Do With Me | Starting Again |
Nothing To Do With Me | Nothing Is The Same |
Nothing To Do With Me | Let\'s Get Back Together |
Nothing To Do With Me | I Knew You Were Magic |
Nothing To Do With Me | Blau |
Nothing To Do With Me | 42 |
Nothing To Do With Me | Not About The Guitar |
Play | The Second Time |
Play | Starting Again |
Play | Nothing Is The Same |
Play | Let\'s Get Back Together |
Play | I Knew You Were Magic |
Play | Blau |
Play | 42 |
Play | Not About The Guitar |
Terrified | Fight Story |
Dies ist der Ausführungsplan:
Im vorherigen Ausführungsplan wurden zusätzliche Sort
-Operatoren vom Abfrageoptimierungstool eingeführt, um die erforderlichen Attribute zu erreichen, die für die Ausführung vom Merge Join erforderlich sind. Die Bedingung JOIN
in der Abfrage dieses Beispiels bezieht sich nur auf AlbumId
, wodurch die Daten nicht gespeichert werden. Daher muss eine Sortierung hinzugefügt werden. Die Abfrage-Engine unterstützt einen Algorithmus für verteiltes Zusammenführen, wodurch die Sortierung lokal und nicht global erfolgen kann und die CPU-Kosten verteilt und parallelisiert werden.
Die resultierenden Übereinstimmungen können auch durch eine Residualbedingung gefiltert werden, bevor sie zurückgegeben werden. Ein Beispiel für Residualbedingungen sind Non-Equality Joins. Aufgrund von zusätzlichen Sortieranforderungen können die Merge-Join-Ausführungspläne sehr komplex sein. Der Hauptalgorithmus eines Merge Join ist auf die Verarbeitung von Inner-, Semi-, Anti- und Outer Join-Varianten ausgelegt.
Push Broadcast Hash Join
Der Operator Push Broadcast Hash Join ist eine verteilte, Hash-Join-basierte Implementierung von SQL-Joins. Der Operator „Push Broadcast Hash Join” liest die Zeilen der Eingabeseite aus, um einen Datenbatch zu erstellen. Dieser Batch wird dann an alle Server gesendet, die Map-Nebendaten enthalten. Auf den Zielservern, auf denen der Batch von Daten empfangen wird, wird ein Hash Join erstellt, wobei der Batch als Build-Nebendaten erstellt und die lokalen Daten dann als Probeseite des Hash Joins gescannt werden.
Push Broadcast Hash Join wird vom Optimierungstool nicht automatisch ausgewählt. Um diesen Operator zu verwenden, legen Sie die Join-Methode für den Abfragehinweis auf PUSH_BROADCAST_HASH_JOIN
fest, wie im folgenden Beispiel gezeigt:
SELECT a.AlbumTitle, s.SongName
FROM Albums AS a JOIN@{join_method=push_broadcast_hash_join} Songs AS s
ON a.SingerId = s.SingerId AND a.AlbumId = s.AlbumId;
Dies sind die Ergebnisse:
AlbumTitle | SongName |
---|---|
Grün | The Second Time |
Green | Starting Again |
Green | Nothing Is The Same |
Grün | Let's Get Back Together |
Grün | I Knew You Were Magic |
Green | Blue |
Green | 42 |
Terrified | Fight Story |
Nothing To Do With Me | Not About The Guitar |
Dies ist der Ausführungsplan:
Die Eingabe für den Push Broadcast Hash Join ist der Index AlbumsByAlbumTitle
.
Diese Eingabe wird in einem Datenbatch serialisiert. Dieser Batch wird dann an alle lokalen Splits des Index SongsBySingerAlbumSongNameDesc
gesendet, wo der Batch dann deserialisiert und in eine Hashtabelle eingebunden wird. Die Hashtabelle verwendet dann die lokalen Indexdaten als Prüfung, die resultierende Übereinstimmungen zurückgibt.
Resultierende Übereinstimmungen können auch durch eine Residualbedingung gefiltert werden, bevor sie zurückgegeben werden. Ein Beispiel für Residualbedingungen sind Non-Equality Joins.
Outer Apply
Der Operator Outer Apply entspricht ungefähr dem Operator Cross Apply. Allerdings wird mit einem Operator des Typs "Outer Apply" gewährleistet, dass bei jeder Ausführung auf der Map-Seite mindestens eine Zeile zurückgegeben wird, wobei bei Bedarf eine mit Nullen aufgefüllte Zeile erstellt wird. Mit anderen Worten bietet er die Semantik für "Left Outer Join".
n-stufige Operatoren
Ein n-stufiger Operator hat mehr als zwei untergeordnete relationale Elemente. Die folgenden n-stufigen Operatoren gibt es:
Union All
Der Operator Union All kombiniert alle Zeilensätze seiner untergeordneten Elemente, ohne Duplikate zu entfernen. "Union All"-Operatoren erhalten ihre Eingabe von Union Input-Operatoren, die auf mehrere Server verteilt sind. Der Operator "Union All" verlangt, dass seine Eingabedaten dasselbe Schema haben, also dieselben Datentypen für jede Spalte verwenden.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT 1 a, 2 b
UNION ALL
SELECT 3 a, 4 b
UNION ALL
SELECT 5 a, 6 b;
Besteht der Zeilentyp für die untergeordneten Elemente aus zwei Ganzzahlen.
Das sind die Ergebnisse:
a | b |
---|---|
1 | 2 |
3 | 4 |
5 | 6 |
Das ist der Ausführungsplan:
Der Operator "Union All" kombiniert die Eingabezeilen und sendet in diesem Beispiel die Ergebnisse an einen Serialize Result-Operator.
Eine Abfrage wie die folgende wäre erfolgreich, da für jede Spalte derselbe Satz von Datentypen verwendet wird, obwohl die untergeordneten Elemente unterschiedliche Variablen für die Spaltennamen verwenden:
SELECT 1 a, 2 b
UNION ALL
SELECT 3 c, 4 e;
Eine Abfrage wie die folgende wäre nicht erfolgreich, da die untergeordneten Elemente unterschiedliche Datentypen für die Spalten verwenden:
SELECT 1 a, 2 b
UNION ALL
SELECT 3 a, 'This is a string' b;
Skalare Teilabfragen
Eine Skalare Teilabfrage ist ein SQL-Teilausdruck eines skalaren Ausdrucks. Spanner versucht, skalare Unterabfragen zu entfernen, wann immer dies möglich ist. In bestimmten Szenarien können Pläne jedoch explizit skalare Teilabfragen enthalten.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT FirstName,
IF(FirstName='Alice',
(SELECT COUNT(*)
FROM Songs
WHERE Duration > 300),
0)
FROM Singers;
Ist dies der SQL-Teilausdruck:
SELECT COUNT(*)
FROM Songs
WHERE Duration > 300;
Dies sind die Ergebnisse der abgeschlossenen Abfrage:
FirstName | |
---|---|
Alice | 1 |
Catalina | 0 |
David | 0 |
Lea | 0 |
Marc | 0 |
Das ist der Ausführungsplan:
Der Ausführungsplan enthält eine skalare Teilabfrage, die als solche oberhalb des Operators Aggregate angezeigt wird.
Spanner wandelt skalare Unterabfragen manchmal in einen anderen Operator wie als Join oder Cross Apply verwenden, um die Leistung zu verbessern.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT *
FROM Songs
WHERE Duration = (SELECT MAX(Duration) FROM Songs);
Ist dies der SQL-Teilausdruck:
SELECT MAX(Duration) FROM Songs;
Dies sind die Ergebnisse der abgeschlossenen Abfrage:
SingerId | AlbumId | TrackId | SongName | Duration | SongGenre |
---|---|---|---|---|---|
2 | 1 | 6 | Nothing Is The Same | 303 | BLUES |
Das ist der Ausführungsplan:
Der Ausführungsplan enthält keine skalare Teilabfrage, da Spanner die skalare Teilabfrage in einen „Cross Apply“-Operator konvertiert hat.
Array-Teilabfragen
Eine Array-Teilabfrage ähnelt einer skalaren Teilabfrage, mit der Ausnahme, dass die Teilabfrage mehr als eine Eingabezeile verbrauchen darf. Die verbrauchten Zeilen werden in ein einzelnes skalares Ausgabearray konvertiert, das pro verbrauchter Eingabezeile ein Element enthält.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT a.AlbumId,
ARRAY(SELECT ConcertDate
FROM Concerts
WHERE Concerts.SingerId = a.SingerId)
FROM Albums AS a;
Das Ist die Teilabfrage:
SELECT ConcertDate
FROM Concerts
WHERE Concerts.SingerId = a.SingerId;
Die Ergebnisse der Teilabfrage für jede AlbumId
werden in ein Array von ConcertDate
-Zeilen für diese AlbumId
konvertiert. Der Ausführungsplan enthält eine Array-Teilabfrage, die als solche oberhalb eines "Distributed Union"-Operators angezeigt wird:
Verteilte Operatoren
Die bisher hier beschriebenen Operatoren werden jeweils nur auf einem einzelnen Gerät ausgeführt. Verteilte Operatoren werden auf mehreren Servern ausgeführt.
Folgende verteilte Operatoren gibt es:
- Distributed Union
- Distributed Merge Union
- Distributed Cross Apply
- Distributed Outer Apply
- Apply Mutations
Der Operator "Distributed Union" bildet die Basis, von der "Distributed Cross Apply" und "Distributed Outer Apply" abgeleitet werden.
Verteilte Operatoren treten in Ausführungsplänen mit einer Distributed Union-Variante über einer oder mehreren Local Distributed Union-Varianten auf. Eine "Distributed Union"-Variante führt die Remoteverteilung von Teilplänen durch. Eine lokale Variante von "Distributed Union" befindet sich über den einzelnen Scans, die für die Abfrage ausgeführt werden, wie in diesem Ausführungsplan gezeigt:
Die lokalen Varianten von "Distributed Union" stellen eine stabile Abfrageausführung sicher, wenn Neustarts zum dynamischen Ändern von Teilungsgrenzen auftreten.
Wann immer es möglich ist, hat eine Variante von "Distributed Union" ein geteiltes Prädikat, das zum "Split Pruning" führt, d. h., dass die Remoteserver Teilpläne nur für die Teilungen ausführen, die das Prädikat erfüllen. Dies verbessert sowohl die Latenzzeit als auch die Gesamtabfrageleistung.
Distributed Union
Der Operator Distributed Union teilt eine oder mehrere Tabellen konzeptionell in mehrere Splits auf, wertet eine Teilabfrage für jeden "Split" unabhängig aus und fasst dann alle Ergebnisse zusammen.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT s.SongName, s.SongGenre
FROM Songs AS s
WHERE s.SingerId = 2 AND s.SongGenre = 'ROCK';
Das sind die Ergebnisse:
SongName | SongGenre |
---|---|
Starting Again | ROCK |
The Second Time | ROCK |
Fight Story | ROCK |
Das ist der Ausführungsplan:
Der Operator "Distributed Union" sendet Teilpläne an die Remoteserver, die einen Tabellenscan der "Splits" ausführen, für die das Prädikat WHERE
s.SingerId = 2 AND s.SongGenre = 'ROCK'
erfüllt ist. Der Operator Serialize Result berechnet die Werte SongName
und SongGenre
aus den Zeilen, die von den Tabellenscans zurückgegeben werden. Der Operator "Distributed Union" gibt dann die kombinierten Ergebnisse von den Remoteservern zurück, wenn die SQL-Abfrageergebnisse vorliegen.
Distributed Merge Union
Der Operator Distributed Merge Union verteilt eine Abfrage auf mehrere Remote-Server. Anschließend werden die Abfrageergebnisse zu einem sortierten Ergebnis kombiniert, das als Distributed Merge Sort bezeichnet wird.
Eine verteilte Merge-Union führt die folgenden Schritte aus:
Der Root-Server sendet eine Unterabfrage an jeden Remote-Server, der eine split der abgefragten Daten. Die Unterabfrage enthält Anweisungen, nach denen die Ergebnisse in einer bestimmten Reihenfolge sortiert werden.
Jeder Remoteserver führt die Unterabfrage für seinen Split aus und sendet die Ergebnisse dann in der angeforderten Reihenfolge zurück.
Der Stammserver führt die sortierte Unterabfrage zusammen, um eine vollständig sortierte Ergebnis.
Die verteilte Zusammenführungsunion ist in Spanner Version 3 und höher standardmäßig aktiviert.
Distributed Cross Apply
Der Operator Distributed Cross Apply (DCA) erweitert den Operator Cross Apply durch die Ausführung auf verschiedenen Servern. Auf der Input-Seite gruppiert DCA Zeilen-Batches, im Gegensatz zu einem regulären "Cross Apply"-Operator, der jeweils nur eine Eingabezeile behandelt. Auf der Map-Seite ist DCA eine Gruppe von "Cross Apply"-Operatoren, die auf Remoteservern ausgeführt werden.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT AlbumTitle FROM Songs
JOIN Albums ON Albums.AlbumId=Songs.AlbumId;
haben die Ergebnisse folgendes Format:
AlbumTitle |
---|
Green |
Nothing To Do With Me |
Play |
Total Junk |
Green |
Das ist der Ausführungsplan:
Der DCA-Eingang enthält einen Index-Scan auf dem Index SongsBySingerAlbumSongNameDesc
, der Reihen von AlbumId
stapelt.
Auf der Map-Seite besteht dieser "Cross Apply"-Operator aus einem Scan des Index AlbumsByAlbumTitle
, abhängig vom Prädikat der AlbumId
in der Eingabezeile, die mit dem Schlüssel AlbumId
im Index AlbumsByAlbumTitle
übereinstimmt. Die Zuordnung gibt den SongName
für die SingerId
-Werte in den zusammengeführten Eingabezeilen zurück.
Der DCA-Vorgang für dieses Beispiel im Überblick: Die Eingabedaten des DCA sind die zu Batches zusammengefassten Zeilen der Tabelle Albums
und die Ausgabedaten ergeben sich aus der Anwendung dieser Zeilen auf die Zuordnung (Map) des Indexscans.
Distributed Outer Apply
Der Operator Distributed Outer Apply erweitert den Operator "Outer Apply" durch die Ausführung auf verschiedenen Servern. Das ähnelt der Vorgehensweise, mit der der Operator "Distributed Cross Apply" den Operator "Cross Apply" erweitert.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT LastName, ConcertDate FROM Singers
LEFT OUTER JOIN@{JOIN_TYPE=APPLY_JOIN} Concerts
ON Singers.SingerId=Concerts.SingerId;
haben die Ergebnisse folgendes Format:
LastName | ConcertDate |
---|---|
Trentor | 2014-02-18 |
Sowa | 2011-09-03 |
Sowa | 2010-06-06 |
Lomond | 2005-04-30 |
Martin | 2015-11-04 |
Richards |
Das ist der Ausführungsplan:
Apply Mutations
Der Operator Apply Mutations wendet die Mutationen aus einer DML-Anweisung auf die Tabelle an. Es ist der oberste Operator in einem Abfrageplan für eine DML-Anweisung.
Wenn Sie zum Beispiel diese Abfrage verwenden:
DELETE FROM Singers
WHERE FirstName = 'Alice';
Das sind die Ergebnisse:
4 rows deleted
This statement deleted 4 rows and did not return any rows.
Das ist der Ausführungsplan:
Weitere Informationen
In diesem Abschnitt werden Elemente beschrieben, die keine eigenständigen Operatoren sind, sondern Aufgaben ausführen, um einen oder mehrere der oben aufgeführten Operatoren zu unterstützen. Die hier beschriebenen Elemente sind technisch gesehen Operatoren, sie können jedoch nicht unabhängig in Ihrem Anfrageplan auftreten.
Struct Constructor
Mit Struct Constructor wird eine Struktur oder eine Auflistung von Feldern erstellt. Normalerweise wird eine Struktur für Zeilen erstellt, die mit dem Operator "Compute" generiert wurden. Der Operator "Struct Constructor" ist nicht eigenständig einsetzbar. Er kommt stattdessen innerhalb der Operatoren Compute Struct oder Serialize Result vor.
Als Teil des Operators "Compute Struct" erstellt "Struct Constructor" eine Struktur, damit die Spalten für die berechneten Zeilen einen einzigen Variablenverweis auf die Struktur verwenden können.
Als Teil des Operators "Serialize Result" erstellt "Struct Constructor" eine Struktur, um die Ergebnisse zu serialisieren.
Wenn Sie zum Beispiel diese Abfrage verwenden:
SELECT IF(TRUE, struct(1 AS A, 1 AS B), struct(2 AS A , 2 AS B)).A;
Das sind die Ergebnisse:
A |
---|
1 |
Das ist der Ausführungsplan:
Im Ausführungsplan werden Operatoren des Typs "Struct Constructor" jeweils innerhalb des Operators "Serialize Result" angezeigt.