Operatori di esecuzione delle query

Introduzione

Questa pagina descrive i dettagli sugli operatori utilizzati in Spanner Piani di esecuzione delle query. Per scoprire come recuperare un piano di esecuzione una query specifica utilizzando la console Google Cloud, consulta Informazioni su come Spanner esegue le query.

Le query e i piani di esecuzione in questa pagina si basano sul seguente schema del database:

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);

Puoi utilizzare le seguenti istruzioni DML (Data Manipulation Language) per aggiungere dati a queste tabelle:

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");

Operatori foglia

Un operatore leaf è un operatore che non ha elementi figlio. I tipi di foglia sono:

Annullamento nidificazione array

Un operatore array unnest consente di appiattire un array di input in righe di elementi. Ogni riga risultante contiene fino a due colonne: il valore effettivo dell'array e, facultativamente, la posizione in base zero nell'array.

Ad esempio, utilizzando questa query:

SELECT a, b FROM UNNEST([1,2,3]) a WITH OFFSET b;

La query appiattisce l'array [1,2,3] nella colonna a e mostra l'array posizione nella colonna b.

Ecco i risultati:

a b
1 0
2 1
3 2

Questo è il piano di esecuzione:

operatore unnest dell&#39;array

Genera relazione

Un operatore genera relazione restituisce zero o più righe.

Relazione unitaria

La relazione unità restituisce una riga. Si tratta di un caso speciale dell'operatore genera relazione.

Ad esempio, utilizzando questa query:

SELECT 1 + 2 AS Result;

Il risultato è:

Risultato
3

Questo è il piano di esecuzione:

operatore di relazione tra unità

Relazione vuota

La relazione vuota non restituisce righe. È un caso speciale della generazione dell'operatore.

Ad esempio, utilizzando questa query:

SELECT * FROM Albums LIMIT 0

Il risultato è:

No results

Questo è il piano di esecuzione:

operatore di relazione vuoto

Scansione

Un operatore scan restituisce righe scansionando una sorgente di righe. Queste sono le tipi di operatori di scansione:

  • Scansione della tabella: l'analisi viene eseguita su una tabella.
  • Scansione dell'indice: la scansione viene eseguita su un indice.
  • Scansione batch: l'analisi viene eseguita su tabelle intermedie create da altri operatori relazionali (ad esempio, una tabella creata applicazione incrociata distribuita).

Se possibile, Spanner applica predicati semplici alle chiavi nell'ambito di una ricerca. Le scansioni vengono eseguite in modo più efficiente quando vengono applicati i predicati, non è necessario leggere l'intera tabella o l'indice. I predicati vengono visualizzati nel piano di esecuzione sotto forma di KeyPredicate: column=value.

Nel peggiore dei casi, una query potrebbe dover cercare in tutte le righe di una tabella. Questa situazione comporta una ricerca completa e viene visualizzata nel piano di esecuzione come full scan: true.

Ad esempio, utilizzando questa query:

SELECT s.LastName
FROM singers@{FORCE_INDEX=SingersByFirstLastName} AS s
WHERE s.FirstName = 'Catalina';

Ecco i risultati:

Cognome
Smith

Questo è il piano di esecuzione:

operatore di scansione

Nel piano di esecuzione, l'operatore unione distribuita di primo livello invia sottopiani ai server remoti. Ogni sottopiano ha un Operatore serialize result e un operatore di scansione dell'indice. Il predicato Key Predicate: FirstName = 'Catalina' limita la ricerca alle righe nell'indice SingersByFirstLastname con FirstName uguale a Catalina. L'output della scansione dell'indice viene restituito all'operatore del risultato di serializzazione.

Operatori unari

Un operatore unario è un operatore che ha un singolo elemento figlio relazionale.

I seguenti operatori sono operatori unari:

Aggregazione

Un operatore aggregate implementa istruzioni SQL GROUP BY e funzioni aggregate (ad esempio COUNT). L'input per un operatore aggregato è suddiviso logicamente in gruppi disposti in colonne chiave (o in un unico gruppo se GROUP BY non è presente). Per ogni gruppo vengono calcolati zero o più valori aggregati.

Ad esempio, utilizzando questa query:

SELECT s.SingerId, AVG(s.duration) AS average, COUNT(*) AS count
FROM Songs AS s
GROUP BY SingerId;

La query raggruppa per SingerId ed esegue un'aggregazione AVG e un aggregazione COUNT.

Ecco i risultati:

SingerId media conteggio
3 278 1
2 225,875 8

Questo è il piano di esecuzione:

operatore aggregato

Gli operatori aggregati possono essere basati su stream o basati su hash. Il piano di esecuzione riportato sopra mostra un aggregato basato su stream. Dati aggregati basati su stream già letti input pre-ordinato (se è presente GROUP BY) e calcola i gruppi senza che bloccano la migrazione. I dati aggregati basati su hash creano tabelle hash per mantenere le dati aggregati di più righe di input contemporaneamente. I dati aggregati basati sui flussi sono e utilizzano meno memoria rispetto agli aggregati basati su hash, ma richiedono l'input per da ordinare (per colonne chiave o indici secondari).

Per scenari distribuiti, un operatore aggregato può essere separato in un locale/globale. Ogni server remoto esegue l'aggregazione locale sulle proprie righe di input e restituisce i risultati al server radice. Il server radice esegue l'aggregazione globale.

Applicare le mutazioni

Un operatore apply mutations applica le mutazioni da una modifica di dati istruzione (DML) alla tabella. È l'operatore principale in un piano di query per un'istruzione DML.

Ad esempio, utilizzando questa query:

DELETE FROM Singers
WHERE FirstName = 'Alice';

Ecco i risultati:

4 rows deleted
This statement deleted 4 rows and did not return any rows.

Questo è il piano di esecuzione:

operatore applica mutazioni

Creazione batch

Un operatore create batch raggruppa le righe di input in una sequenza. Un'operazione di creazione di un batch avviene in genere nell'ambito di un'operazione di join distribuito. Le righe di input possono essere riordinate durante l'aggregazione. Il numero di righe di input raggruppate in batch in ogni esecuzione dell'operatore batch è variabile.

Consulta l'operatore Distributed Cross apply per un esempio di un operatore di creazione batch in un piano di esecuzione.

Computing

Un operatore compute produce output leggendo le righe di input e aggiungendo uno o più colonne aggiuntive calcolate tramite espressioni scalari. Consulta le Operatore union all per un esempio di operatore di computing in una di esecuzione del piano di controllo.

struct di computing

Un operatore compute struct crea una variabile per una struttura che contiene campi per ciascuna delle colonne di input.

Ad esempio, utilizzando questa query:

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;

Ecco i risultati:

Nome Non specificato
Alice [["Non sulla chitarra","BLUES"]]

Questo è il piano di esecuzione:

Operatore struct di calcolo

Nel piano di esecuzione, l'operatore di sottoquery dell'array riceve l'input da un dell'operatore distribuito, che riceve input da un Compute Engine. L'operatore struct Compute crea una struttura le colonne SongName e SongGenre nella tabella Songs.

Filtro

Un operatore filter legge tutte le righe dal proprio input e applica un predicato scalare ogni riga, poi restituisce solo le righe che soddisfano il predicato.

Ad esempio, utilizzando questa query:

SELECT s.LastName FROM (SELECT s.LastName
FROM Singers AS s LIMIT 3) s
WHERE s.LastName LIKE 'Rich%';

Ecco i risultati:

Cognome
Richards

Questo è il piano di esecuzione:

operatore di filtro

Il predicato per i cantanti il cui cognome inizia con Rich è implementato come filtro. L'input del filtro è l'output di una scansione dell'indice e la l'output del filtro è costituito da righe in cui LastName inizia con Rich.

Per le prestazioni, ogni volta che un filtro è posizionato direttamente sopra una scansione, influisce sulla modalità di lettura dei dati. Ad esempio, considera una tabella con chiave k. Un filtro con il predicato k = 5 direttamente sopra una scansione della tabella cercherà le righe corrispondenti a k = 5, senza leggere l'intero input. Ciò comporta un'esecuzione più efficiente della query. Nell'esempio precedente, l'operatore di filtro legge solo le righe che soddisfano il predicato WHERE s.LastName LIKE 'Rich%'.

Filtra scansione

Un operatore di scansione filtrata è sempre sopra una scansione di tabelle o indici. Utilizza la scansione per ridurre il numero di righe lette dal database e la scansione risultante è generalmente più rapida rispetto a un filtro. Spanner applica la scansione dei filtri in determinate condizioni:

  • Condizione cercabile: la condizione cercabile si applica se Spanner può determinare una riga specifica a cui accedere nella tabella. In genere, questo accade quando il filtro si trova su un prefisso della chiave primaria. Ad esempio, se la chiave primaria è composta da Col1 e Col2, è possibile eseguire ricerche in una clausola WHERE che include valori espliciti per Col1 o per Col1 e Col2. In questo caso, Spanner legge i dati solo nell'intervallo di chiavi.
  • Condizione residua: qualsiasi altra condizione in cui Spanner può valutare per limitare la quantità di dati letti.

Ad esempio, utilizzando questa query:

SELECT LastName
FROM Singers
WHERE SingerId = 1

Ecco i risultati:

Cognome
Richards

Questo è il piano di esecuzione:

operatore di scansione del filtro

Limite

Un operatore limit limita il numero di righe restituite. Un'etichetta facoltativa Il parametro OFFSET specifica la riga iniziale da restituire. Per la distribuzione scenari possibili, un operatore di limite può essere separato in una coppia locale/globale. Ciascuna server remoto applica il limite locale per le righe di output, quindi restituisce i risultati al server radice. Il server radice aggrega le righe inviate tra i server remoti e poi applica il limite globale.

Ad esempio, utilizzando questa query:

SELECT s.SongName
FROM Songs AS s
LIMIT 3;

Ecco i risultati:

SongName
Not About The Guitar
La seconda volta
Ricominciare

Questo è il piano di esecuzione:

operatore LIMIT

Il limite locale è il limite per ciascun server remoto. Il server radice aggrega le righe dai server remoti, quindi applica il limite globale.

Assegnazione ID casuale

Un operatore random idAssign produce l'output leggendo le relative righe di input e aggiungendo un numero casuale a ogni riga. Funziona con un operatore Filter o Sort per ottenere i metodi di campionamento. I metodi di campionamento supportati sono Bernoulli e Reservoir.

Ad esempio, la seguente query utilizza il campionamento di Bernoulli con una frequenza di campionamento del 10%.

SELECT s.SongName
FROM Songs AS s TABLESAMPLE BERNOULLI (10 PERCENT);

Ecco i risultati:

SongName
Ricominciare
Nothing Is The Same

Poiché il risultato è un campione, può variare ogni volta che viene eseguita anche se la query è la stessa.

Questo è il piano di esecuzione:

operatore di esempio bernoulli

In questo piano di esecuzione, l'operatore Random Id Assign riceve un input da un operatore Distributed Union, che riceve il suo input da una scansione dell'indice. L'operatore restituisce le righe con ID casuali e l'operatore Filter applica quindi uno scalare sugli ID casuali e restituisce circa il 10% delle righe.

L'esempio seguente utilizza il campionamento Reservoir con una frequenza di campionamento di 2 righe.

SELECT s.SongName
FROM Songs AS s TABLESAMPLE RESERVOIR (2 ROWS);

Ecco i risultati:

SongName
Sapevo che eri magia
La seconda volta

Tieni presente che, poiché il risultato è un campione, potrebbe variare ogni volta che viene eseguita la query, anche se è la stessa.

Questo è il piano di esecuzione:

operatore di esempio reservoir

In questo piano di esecuzione, l'operatore Random Id Assign riceve un input da un operatore Distributed Union, che riceve il suo input da una scansione dell'indice. L'operatore restituisce le righe con ID casuali e l'operatore Sort applica l'ordinamento agli ID casuali e applica LIMIT con 2 righe.

Serializza risultato

Un operatore serializza risultato è un caso speciale dell'operatore struct compute che serializza ogni riga del risultato finale della query, per tornare di alto profilo.

Ad esempio, utilizzando questa query:

SELECT ARRAY(SELECT AS STRUCT so.SongName, so.SongGenre
             FROM Songs AS so
             WHERE so.SingerId = s.SingerId)
FROM Singers AS s;

La query richiede un array di SongName e SongGenre in base a SingerId.

Ecco i risultati:

Non specificato
[]
[[Ritorniamo insieme, COUNTRY], [Ricominciamo, ROCK]]
[[Non sulla chitarra, BLUES]]
[]
[]

Questo è il piano di esecuzione:

Operatore del risultato serializza

L'operatore del risultato di serializzazione crea un risultato che contiene, per ogni riga di la tabella Singers, un array di SongName e SongGenre coppie per i brani dal cantante.

Ordina

Un operatore ordina legge le righe di input, le ordina per colonna o colonne e poi restituisce i risultati ordinati.

Ad esempio, utilizzando questa query:

SELECT s.SongGenre
FROM Songs AS s
ORDER By SongGenre;

Ecco i risultati:

SongGenre
BLU
BLU
BLU
BLU
CLASSICAL
PAESE
ROCCIA
ROCCIA
ROCCIA

Questo è il piano di esecuzione:

operatore di ordinamento

In questo piano di esecuzione, l'operatore di ordinamento riceve le righe di input da un operatore unione distribuita, le ordina e restituisce le righe ordinate a un operatore serializza risultato.

Per limitare il numero di righe restituite, un operatore di ordinamento può facoltativamente avere Parametri LIMIT e OFFSET. Per scenari distribuiti, viene utilizzato un operatore di ordinamento un operatore LIMIT e/o OFFSET è separato in una coppia locale/globale. Ciascuna server remoto applica l'ordinamento e il limite/offset locale per l'input righe, poi restituisce i risultati al server radice. Il server radice aggrega le righe inviate dai server remoti, le ordina e poi applica il limite/l'offset globale.

Ad esempio, utilizzando questa query:

SELECT s.SongGenre
FROM Songs AS s
ORDER By SongGenre
LIMIT 3;

Ecco i risultati:

SongGenre
BLU
BLU
BLUES

Questo è il piano di esecuzione:

operatore di ordinamento con limite

Il piano di esecuzione mostra il limite locale per i server remoti e il limite globale per il server radice.

TVF

Un operatore di funzione con valore di tabella produce l'output leggendo le relative righe di input e applicando la funzione specificata. La funzione potrebbe implementare la mappatura e restituire lo stesso numero di righe dell'input. Può anche essere un generatore che restituisce più righe o un filtro che restituisce meno righe.

Ad esempio, utilizzando questa query:

SELECT Genre, SongName
FROM ML.PREDICT(MODEL GenreClassifier, Table Songs)

Ecco i risultati:

Genere SongName
Paese Non riguarda la chitarra
Roccia La seconda volta
Pop Ricomincia
Pop Niente è uguale
Paese Let's Get Back Together
Pop I Knew You Were Magic
Elettronica Blu
Roccia 42
Rock Storia di un combattimento

Questo è il piano di esecuzione:

operatore tvf

Input unione

Un operatore union input restituisce i risultati a un operatore union all. Consulta l'operatore union all per un esempio di operatore di input unione in un piano di esecuzione.

Operatori binari

Un operatore binario è un operatore con due elementi figlio di tipo relazionale. La gli operatori che seguono sono operatori binari:

Applicazione incrociata

Un operatore cross apply esegue una query tabella su ogni riga recuperata dalla query un'altra tabella e restituisce l'unione di tutte le esecuzioni di query di tabella. Applicazione incrociata e gli operatori outer apply eseguono l'elaborazione orientata alle righe. a differenza degli operatori che eseguono l'elaborazione basata su set, come hash iscriviti . L'operatore di applicazione incrociata ha due input, input e map. L'operatore Cross Apply applica ogni riga del lato di input al lato mappa. La il risultato dell'applicazione incrociata ha colonne sia sul lato di input sia su quello della mappa.

Ad esempio, utilizzando questa query:

SELECT si.FirstName,
  (SELECT so.SongName
   FROM Songs AS so
   WHERE so.SingerId=si.SingerId
   LIMIT 1)
FROM Singers AS si;

La query richiede il nome di ogni cantante, insieme al nome di un solo brano del cantante.

Ecco i risultati:

Nome Non specificato
Alice Not About The Guitar
Catalina Ritorniamo insieme
Davide NULL
Elena NULL
Marc NULL

La prima colonna viene compilata dalla tabella Singers e la seconda colonna compilate dalla tabella Songs. Nei casi in cui esisteva un SingerId in Singers ma non era presente SingerId corrispondente nella tabella Songs, la la seconda colonna contiene NULL.

Questo è il piano di esecuzione:

operatore cross apply

Il nodo di primo livello è un operatore Distributed Union. La L'operatore di Distributed Union distribuisce i sottopiani ai server remoti. Il sottopiano contiene un operatore serializza il risultato che calcola il il nome della cantante e il nome di una delle sue canzoni e serializza ogni riga dell'output.

L'operatore del risultato di serializzazione riceve l'input da un operatore di applicazione incrociata. Il lato di input dell'operatore applica tra tabelle è una scansione della tabella sulla tabella Singers.

Il lato mappa per l'operazione di applicazione incrociata contiene quanto segue (dall'alto a in basso):

  • Un operatore di aggregazione che restituisce Songs.SongName.
  • Un operatore limit che limita il numero di brani restituiti a uno per interprete.
  • Una scansione dell'indice SongsBySingerAlbumSongNameDesc.

L'operatore di applicazione incrociata mappa ogni riga dal lato di input a una riga nella mappa con lo stesso SingerId. L'output dell'operatore applica tra tabelle è il valore FirstName della riga di input e il valore SongName della riga della mappa. (Il valore SongName sarà NULL se non esiste una riga della mappa corrispondente SingerId.) L'operatore di Distributed Union nella parte superiore del piano di esecuzione combina tutte le righe di output dei server remoti e le restituisce come i risultati della query.

Join hash

Un operatore di join hash è un'implementazione basata su hash dei join SQL. I join hash eseguono l'elaborazione basata su set. L'operatore di join hash legge le righe dall'input contrassegnato come build e lo inserisce in una tabella hash in base a una condizione di join. L'operatore di join hash legge quindi le righe dall'input contrassegnato come probe. Per ogni riga che legge dall'input del probe, l'operatore di join hash cerca righe nella tabella hash. L'operatore di join hash restituisce le righe corrispondenti come o il risultato finale.

Ad esempio, utilizzando questa query:

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;

Ecco i risultati:

AlbumTitle SongName
Nothing To Do With Me Not About The Guitar
Verde La seconda volta
Verde Ricominciare
Verde Niente è uguale
Verde Ritorniamo insieme
Verde Sapevo che eri magia
Verde Blu
Verde 42
Terrorizzato Storia di un combattimento

Questo è il piano di esecuzione:

Operatore di join hash

Nel piano di esecuzione, build è un'unione distribuita che distribuisce le analisi nella tabella Albums. Probe è un operatore di unione distribuito che distribuisce le scansioni nell'indice SongsBySingerAlbumSongNameDesc. L'operatore di join hash legge tutte le righe dal lato build. Ogni riga di build posizionati in una tabella hash in base alle colonne nella condizione a.SingerId = s.SingerId AND a.AlbumId = s.AlbumId. Successivamente, l'operatore di join con hash legge tutte le righe dal lato della sonda. Per ogni riga del probe, l'operatore di join hash cerca corrispondenze nella tabella hash. Le corrispondenze risultanti vengono restituite dal join hash dell'operatore telefonico.

Le corrispondenze risultanti nella tabella hash possono anche essere filtrate in base a una condizione residua prima che vengano restituiti. (Un esempio di dove appaiono condizioni residue è join non di uguaglianza). I piani di esecuzione Hash join possono essere complessi a causa della memoria gestire e unire le varianti. L'algoritmo di join hash principale è adattato per gestire le varianti di join interno, semi, anti e esterno.

Join di unione

Un operatore di join per unione è un'implementazione basata su unione di un join SQL. Entrambi i lati dell'unione producono righe ordinate in base alle colonne utilizzate nella condizione di join. La join di unione utilizza contemporaneamente entrambi gli stream di input e genera righe quando la condizione di join è soddisfatta. Se gli input non sono ordinati originariamente come richiesto poi l'ottimizzatore aggiunge operatori Sort espliciti al piano.

Il join unione non viene selezionato automaticamente dall'ottimizzatore. Per utilizzare questo operatore, imposta il metodo di join su MERGE_JOIN nell'indicazione della query, come mostrato nell'esempio seguente:

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;

Ecco i risultati:

AlbumTitle SongName
Verde La seconda volta
Verde Ricominciare
Verde Niente è uguale
Verde Ritorniamo insieme
Verde Sapevo che eri magia
Verde Blu
Verde 42
Terrorizzato Storia di un combattimento
Nothing To Do With Me Non riguarda la chitarra

Questo è il piano di esecuzione:

Operatore di join di unione_1

In questo piano di esecuzione, l'unione per accodamento viene distribuita in modo che venga eseguita dove si trovano i dati. Questo consente anche al join in questo esempio operano senza l'introduzione di altri operatori di ordinamento, poiché entrambi le scansioni delle tabelle sono già ordinate per SingerId, AlbumId, che è il join . In questo piano, la scansione sul lato sinistro della tabella Albums avanza ogni volta che il suo SingerId, AlbumId è relativamente meno della mano destra scansione indice SongsBySingerAlbumSongNameDesc lato SongsBySingerAlbumSongNameDesc SingerId_1, AlbumId_1 coppia. Analogamente, il lato destro avanza ogni volta che è inferiore al lato sinistra. L'avanzata della fusione continua a cercare equivalenze tali da le corrispondenze risultanti.

Considera un altro esempio di join di unione utilizzando la seguente query:

SELECT a.AlbumTitle, s.SongName
FROM Albums AS a JOIN@{join_method=merge_join} Songs AS s
ON a.AlbumId = s.AlbumId;

Questo genera i seguenti risultati:

AlbumTitle SongName
Spazzatura totale La seconda volta
Spazzatura totale Ricominciare
Spazzatura totale Niente è uguale
Spazzatura totale Let\'s Get Back Together
Rifiuti totali Sapevo che eri magia
Rifiuti totali Blu
Rifiuti totali 42
Spazzatura totale Non riguarda la chitarra
Verde La seconda volta
Verde Ricominciare
Verde Niente è uguale
Verde Ritorniamo insieme
Verde Sapevo che eri magia
Verde Blu
Verde 42
Verde Not About The Guitar
Nothing To Do With Me La seconda volta
Nothing To Do With Me Ricominciare
Niente da fare con me Nothing Is The Same
Nothing To Do With Me Let\'s Get Back Together
Niente da fare con me Sapevo che eri magia
Niente da fare con me Blu
Niente da fare con me 42
Nothing To Do With Me Not About The Guitar
Riproduci La seconda volta
Riproduci Ricomincia
Riproduci Niente è uguale
Riproduci Ritorniamo insieme
Riproduci Sapevo che eri magia
Riproduci Blu
Riproduci 42
Riproduci Not About The Guitar
Terrorizzato Storia di un combattimento

Questo è il piano di esecuzione:

Operatore di join di unione_2

Nel piano di esecuzione precedente, l'ottimizzatore delle query ha introdotto operatori Sort aggiuntivi per ottenere le proprietà necessarie per l'esecuzione della join di unione. La condizione JOIN nella query di questo esempio è attiva solo AlbumId, che non è la modalità di archiviazione dei dati, quindi è necessario aggiungere un ordinamento. La il motore di query supporta un algoritmo di unione distribuita, consentendo di effettuare l'ordinamento localmente anziché globalmente, il che distribuisce e parallelizza il costo della CPU.

Le corrispondenze risultanti possono anche essere filtrate in base a una condizione residua prima vengono restituiti. (Un esempio di condizione in cui appaiono condizioni residue è senza uguaglianza . I piani di esecuzione di Merge join possono essere complessi a causa di ulteriori ordinamenti i tuoi requisiti. L'algoritmo principale di unione dei join è adattato per gestire ed outer join.

Push join hash join

Un operatore di unione hash delle trasmissioni push è un sistema distribuito basato su join hash dei join SQL. L'operatore di join hash della trasmissione push legge le righe da dal lato di input per costruire un batch di dati. Il batch viene quindi per la trasmissione a tutti i server contenenti dati a livello di mappa. Sui server di destinazione in cui viene ricevuto il batch di dati, viene creata un'unione hash utilizzando il batch come dati lato build e i dati locali vengono quindi analizzati come lato di prova dell'unione hash.

L'unione hash della trasmissione push non viene selezionata automaticamente dall'ottimizzatore. A Usa questo operatore, imposta il metodo di join su PUSH_BROADCAST_HASH_JOIN il suggerimento per la query, come mostrato nell'esempio seguente:

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;

Ecco i risultati:

AlbumTitle SongName
Verde La seconda volta
Verde Ricominciare
Verde Niente è uguale
Verde Lets Get Back Together
Verde Sapevo che eri magia
Verde Blu
Verde 42
Terrorizzato Storia di un combattimento
Nothing To Do With Me Non riguarda la chitarra

Questo è il piano di esecuzione:

Operatore push_broadcast hash_join

L'input per l'unione hash di trasmissione push è l'indice AlbumsByAlbumTitle. L'input viene serializzato in un batch di dati. Il batch viene quindi inviato le suddivisioni locali dell'indice SongsBySingerAlbumSongNameDesc, dove il batch viene quindi deserializzato e integrato in una tabella hash. La tabella hash utilizza quindi i dati dell'indice locale come probe che restituisce le corrispondenze risultanti.

Le corrispondenze risultanti possono anche essere filtrate in base a una condizione residua prima restituito. (Un esempio di dove appaiono condizioni residue è join non di uguaglianza).

Applicazione esterna

Un operatore di applicazione esterna è simile a un operatore di applicazione incrociata, ad eccezione di un operatore outer apply per garantire che ogni esecuzione sul lato della mappa restituisce almeno una riga Produzione di una riga riempita con NULL, se necessario. In altre parole, fornisce la semantica del join esterno sinistro.

Operatori n-ari

Un operatore N-ary è un operatore con più di due elementi figlio relazionali. I seguenti operatori sono operatori N-ary:

Unisci tutto

Un operatore union all combina tutti gli insiemi di righe dei relativi figli senza rimuovere i duplicati. Union tutti gli operatori ricevono l'input da union di input distribuiti su più server. L'operatore union all richiede che i relativi input abbiano lo stesso schema, ovvero lo stesso insieme di tipi di dati per ogni colonna.

Ad esempio, utilizzando questa query:

SELECT 1 a, 2 b
UNION ALL
SELECT 3 a, 4 b
UNION ALL
SELECT 5 a, 6 b;

Il tipo di riga per gli elementi secondari è composto da due numeri interi.

Ecco i risultati:

a b
1 2
3 4
5 6

Questo è il piano di esecuzione:

union_all_operator

L'operatore union all combina le righe di input e, in questo esempio, invia a un operatore di serializza il risultato.

Una query come la seguente potrebbe avere esito positivo, perché lo stesso insieme di tipi di dati viene utilizzato per ogni colonna, anche se gli elementi secondari usano variabili diverse per i nomi delle colonne:

SELECT 1 a, 2 b
UNION ALL
SELECT 3 c, 4 e;

Una query come la seguente non andrebbe a buon fine perché i figli utilizzano diversi tipi di dati per le colonne:

SELECT 1 a, 2 b
UNION ALL
SELECT 3 a, 'This is a string' b;

Sottoquery scalari

Una sottoquery scalare è una sottoespressione SQL che fa parte di un'espressione scalare. Spanner tenta di rimuovere le sottoquery scalari laddove possibile. Tuttavia, in alcuni casi i piani possono contenere esplicitamente sottoquery scalari.

Ad esempio, utilizzando questa query:

SELECT FirstName,
IF(FirstName='Alice',
   (SELECT COUNT(*)
    FROM Songs
    WHERE Duration > 300),
   0)
FROM Singers;

Questa è la sottoespressione SQL:

SELECT COUNT(*)
FROM Songs
WHERE Duration > 300;

Questi sono i risultati (della query completa):

Nome
Alice 1
Catalina 0
Davide 0
Elena 0
Marc 0

Questo è il piano di esecuzione:

Operatore di sottoquery scalare

Il piano di esecuzione contiene una sottoquery scalare, indicata come Sottoquery scalare, sopra un operatore aggregato.

A volte Spanner converte le sottoquery scalari in un altro operatore, ad esempio una join o un'applicazione incrociata, per migliorare le prestazioni.

Ad esempio, utilizzando questa query:

SELECT *
FROM Songs
WHERE Duration = (SELECT MAX(Duration) FROM Songs);

Questa è la sottoespressione SQL:

SELECT MAX(Duration) FROM Songs;

Ecco i risultati (della query completa):

SingerId AlbumId TrackId SongName Durata SongGenre
2 1 6 Nothing Is The Same 303 BLU

Questo è il piano di esecuzione:

operatore di sottoquery scalare non visualizzato nel piano

Il piano di esecuzione non contiene una sottoquery scalare perché Spanner ha convertito la sottoquery scalare in un'applicazione incrociata.

Sottoquery di array

Una sottoquery di array è simile a una sottoquery scalare, ad eccezione del fatto che la sottoquery è può consumare più di una riga di input. Le righe utilizzate vengono convertite in un singolo array di output scalare contenente un elemento per riga di input utilizzata.

Ad esempio, utilizzando questa query:

SELECT a.AlbumId,
ARRAY(SELECT ConcertDate
      FROM Concerts
      WHERE Concerts.SingerId = a.SingerId)
FROM Albums AS a;

Questa è la sottoquery:

SELECT ConcertDate
FROM Concerts
WHERE Concerts.SingerId = a.SingerId;

I risultati della sottoquery per ogni AlbumId vengono convertiti in un array di ConcertDate righe rispetto a AlbumId. Il piano di esecuzione contiene un array sottoquery, mostrata come Subquery array, sopra un operatore di unione distribuita:

operatore di sottoquery dell&#39;array

Operatori distribuiti

Gli operatori descritti in precedenza in questa pagina vengono eseguiti entro i confini di una singola macchina. Gli operatori distribuiti vengono eseguiti su più server.

I seguenti operatori sono operatori distribuiti:

L'operatore di unione distribuita è l'operatore primitivo da cui vengono ricavate cross apply e Distributed Outer apply.

Gli operatori distribuiti compaiono nei piani di esecuzione con un unione distribuita variante in cima a una o più varianti dell'unione distribuita locale. R la variante Distributed Union esegue la distribuzione remota dei sottopiani. Un locale la variante Distributed Union è al di sopra di ogni scansione eseguita come mostrato in questo piano di esecuzione:

operatore distribuito

Le varianti di unione distribuita locale assicurano un'esecuzione stabile delle query quando si verificano riavvii per la modifica dinamica dei confini di suddivisione.

Quando possibile, una variante Distributed Union ha un predicato split che comporta l'eliminazione della suddivisione, vale a dire che i server remoti eseguono i sottopiani solo le suddivisioni che soddisfano il predicato. Questo migliora sia la latenza che in generale le prestazioni della query.

Unione distribuita

Un operatore Distributed Union divide concettualmente una o più tabelle in più split, valuta in remoto una sottoquery in modo indipendente su ogni suddivisione e quindi unisce tutti i risultati.

Ad esempio, utilizzando questa query:

SELECT s.SongName, s.SongGenre
FROM Songs AS s
WHERE s.SingerId = 2 AND s.SongGenre = 'ROCK';

Ecco i risultati:

SongName SongGenre
Ricominciare ROCCIA
La seconda volta ROCCIA
Storia di un combattimento ROCCIA

Questo è il piano di esecuzione:

operatore Distributed Union

L'operatore Distributed Union invia dei sottopiani ai server remoti, che eseguono scansiona la tabella tra le suddivisioni che soddisfano il predicato WHERE s.SingerId = 2 AND s.SongGenre = 'ROCK' della query. A serializza la serie l'operatore result calcola SongName e SongGenre dalle righe restituite dalle scansioni delle tabelle. L'operatore Distributed Union restituisce quindi i risultati combinati dai server remoti sotto forma di query SQL che consentono di analizzare i dati e visualizzare i risultati.

Unione distribuita distribuita

L'operatore DistributedMerge Union distribuisce una query su più server remoti. Quindi, combina i risultati della query per produrre un risultato ordinato, noto come ordinamento di unione distribuito.

Un'unione di unione distribuita esegue i seguenti passaggi:

  1. Il server radice invia una sottoquery a ogni server remoto che ospita una suddiviso dei dati sottoposti a query. La sottoquery include istruzioni che portano all'ordinamento dei risultati in un ordine specifico.

  2. Ogni server remoto esegue la sottoquery sulla propria suddivisione e restituisce i risultati nell'ordine richiesto.

  3. Il server radice unisce la sottoquery ordinata per produrre una query completamente ordinata o il risultato finale.

L'unione per unione distribuita è attiva per impostazione predefinita per Spanner 3 e versioni successive.

Operazione di join distribuita

Un operatore Distributed Cross apply (DCA) estende l'cross apply eseguendo l'operazione su più server. L'input del DCA gruppi laterali di batch di righe (a differenza di un normale operatore cross apply, che agisce solo in una riga di input alla volta). Il lato della mappa DCA è un insieme di criteri cross apply o operatori in esecuzione su server remoti.

Ad esempio, utilizzando questa query:

SELECT AlbumTitle FROM Songs
JOIN Albums ON Albums.AlbumId=Songs.AlbumId;

I risultati sono nel formato:

AlbumTitle
Verde
Nothing To Do With Me
Riproduci
Spazzatura totale
Verde

Questo è il piano di esecuzione:

operatore Distributed Cross Apply

L'input DCA contiene una scansione dell'indice sull'indice SongsBySingerAlbumSongNameDesc che raggruppa le righe di AlbumId. Il lato della mappa per questo operatore di applicazione incrociata è una scansione dell'indice AlbumsByAlbumTitle, soggetto al predicato AlbumId nella riga di input corrispondente alla chiave AlbumId nell'indice AlbumsByAlbumTitle. La mappatura restituisce SongName per i valori SingerId nelle righe di input raggruppate.

Per riepilogare il processo DCA per questo esempio, l'input del DCA è l'input righe dalla tabella Albums e l'output del DCA è l'applicazione di questi righe alla mappa della scansione dell'indice.

Applicazione esterna distribuita

Un operatore Distributed Outer apply estende la funzione operatore di applicazione esterna eseguendo su più in modo simile a come un operatore Distributed Cross apply estende un modello .

Ad esempio, utilizzando questa query:

SELECT LastName, ConcertDate FROM Singers
LEFT OUTER JOIN@{JOIN_TYPE=APPLY_JOIN} Concerts
ON Singers.SingerId=Concerts.SingerId;

I risultati sono nel formato:

Cognome ConcertDate
Trentor 2014-02-18
Rossi 2011-09-03
Rossi 2010-06-06
Lomond 2005-04-30
Martin 2015-11-04
Richards

Questo è il piano di esecuzione:

operatore Distributed Outer apply

Applicare le mutazioni

Un operatore apply mutations applica le mutazioni di un'istruzione di manipolazione dei dati (DML) alla tabella. È l'operatore principale in un piano di query per un'istruzione DML.

Ad esempio, utilizzando questa query:

DELETE FROM Singers
WHERE FirstName = 'Alice';

Ecco i risultati:

4 rows deleted
This statement deleted 4 rows and did not return any rows.

Questo è il piano di esecuzione:

operatore di applicazione delle mutazioni

Informazioni aggiuntive

Questa sezione descrive gli elementi che non sono operatori autonomi, ma che invece eseguono attività per supportare uno o più degli operatori sopra elencati. Elementi descritti qui sono operatori tecnicamente, ma non sono operatori separati in il tuo piano di query.

Costruttore di struct

Un costruttore di struct crea una struct o una raccolta di campi. Generalmente crea una struct per le righe risultanti da un'operazione di calcolo. Un costruttore di struct non è un operatore autonomo. Viene invece visualizzato negli operatori compute struct o serialize result.

Per un'operazione di calcolo della struttura, il costruttore della struttura crea una struttura in modo che le colonne per le righe calcolate possano utilizzare un singolo riferimento di variabile alla struttura.

Per un'operazione di serializzazione dei risultati, il costruttore della struct crea una struct per eseguire la serializzazione dei risultati.

Ad esempio, utilizzando questa query:

SELECT IF(TRUE, struct(1 AS A, 1 AS B), struct(2 AS A , 2 AS B)).A;

Ecco i risultati:

A
1

Questo è il piano di esecuzione:

Costruttore di struct

Nel piano di esecuzione, i costruttori di struct vengono visualizzati all'interno di un operatore di serializzazione del risultato.