Panoramica
Questa pagina fornisce concetti sui piani di esecuzione delle query e su come vengono utilizzati Spanner per eseguire query in un ambiente distribuito. Per ulteriori informazioni per recuperare un piano di esecuzione per una query specifica Nella console Google Cloud, consulta Comprendere l'esecuzione di Spanner query. Puoi anche visualizzare piani di query storiche campionati e confrontare le prestazioni di una query nel tempo per determinate query. Per saperne di più, vedi Piani di query campionati.
Spanner utilizza istruzioni SQL dichiarative per eseguire query sui propri database. Le istruzioni SQL definiscono cosa vuole l'utente senza specificare come ottenere i risultati. Un piano di esecuzione query è l'insieme di passaggi relativi al modo in cui vengono generati disponibili. Per una determinata istruzione SQL, ci possono essere più modi per ottenere i risultati. Lo ottimizzatore delle query di Spanner valuta diversi piani di esecuzione e sceglie quello che considera più efficiente. Spanner utilizza quindi il piano di esecuzione per recuperare i risultati.
Concettualmente, un piano di esecuzione è un albero di operatori relazionali. Ogni operatore legge le righe degli input e produce le righe di output. Il risultato l'operatore alla radice dell'esecuzione viene restituito come risultato query.
Ad esempio, questa query:
SELECT s.SongName FROM Songs AS s;
produce un piano di esecuzione delle query, che può essere visualizzato come:
Le query e i piani di esecuzione in questa pagina si basano sul seguente database schema:
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 in 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");
Ottenere piani di esecuzione efficienti è difficile perché Spanner suddivide i dati in divisioni. Le suddivisioni possono spostarsi in modo indipendente l'una dall'altra e vengono assegnati a server diversi, che potrebbero trovarsi in posizioni fisiche diverse luoghi. Per valutare i piani di esecuzione sui dati distribuiti, Spanner utilizza l'esecuzione in base a:
- esecuzione locale di sottopiani nei server che contengono i dati
- l'orchestrazione e l'aggregazione di più esecuzioni remote con eliminazione della distribuzione
Spanner utilizza l'operatore primitivo distributed union
,
insieme alle sue varianti distributed cross apply
e
distributed outer apply
, per abilitare questo modello.
Piani di query campionati
I piani di query campionate di Spanner consentono di visualizzare esempi di query piani di query e confrontarne le prestazioni nel tempo. Non tutte le query per creare piani di query campionati. Solo le query che consumano più CPU possono campionare. La conservazione dei dati per gli esempi di piano di query di Spanner è 30 giorni. Puoi trovare esempi di piani di query nella pagina Approfondimenti sulle query di la console Google Cloud. Per istruzioni, consulta Visualizzare i piani di query campionate.
L'anatomia di un piano di query campionato è la stessa di una normale esecuzione di query e il piano d'azione. Per ulteriori informazioni su come comprendere i piani visivi e utilizzarli per eseguire il debug delle query. Consulta Un tour del visualizzatore del piano di query.
Casi d'uso comuni per i piani di query campionate:
Alcuni casi d'uso comuni per i piani di query campionate includono:
- Osserva le modifiche al piano di query dovute a modifiche allo schema (ad esempio, l'aggiunta o la rimozione di un indice).
- Osserva le modifiche del piano di query dovute a un aggiornamento della versione dello strumento di ottimizzazione.
- Osservare le modifiche al piano di query dovute alle nuove statistiche di ottimizzazione.
raccolti automaticamente ogni tre giorni o manualmente
il comando
ANALYZE
.
Se le prestazioni di una query mostrano una differenza significativa nel tempo o se Se vuoi migliorare le prestazioni di una query, consulta le best practice per SQL per creare istruzioni di query ottimizzate che aiutano Spanner a trovare piani di esecuzione più efficienti.
La vita di una query
Una query SQL in Spanner viene prima compilata in un piano di esecuzione, quindi inviato a un server root iniziale per l'esecuzione. Il server radice è scelto in modo da ridurre al minimo il numero di hop per raggiungere i dati sottoposti a query. La principale:
- avvia l'esecuzione remota dei sottopiani (se necessario)
- attende i risultati delle esecuzioni remote
- gestisce eventuali passaggi rimanenti di esecuzione locale, come l'aggregazione dei risultati
- restituisce i risultati per la query
I server remoti che ricevono un sottopiano fungono da "root" server per i loro seguendo lo stesso modello del server principale di livello più alto. Il risultato è un delle esecuzioni remote. Concettualmente, l'esecuzione delle query fluisce dall'alto inferiore e i risultati della query vengono restituiti dal basso verso l'alto.Il diagramma seguente mostra questo pattern:
I seguenti esempi illustrano questo modello in modo più dettagliato.
Query aggregate
Una query aggregata implementa le query GROUP BY
.
Ad esempio, utilizzando questa query:
SELECT s.SingerId, COUNT(*) AS SongCount
FROM Songs AS s
WHERE s.SingerId < 100
GROUP BY s.SingerId;
Ecco i risultati:
+----------+-----------+
| SingerId | SongCount |
+----------+-----------+
| 3 | 1 |
| 2 | 8 |
+----------+-----------+
Concettualmente, questo è il piano di esecuzione:
Spanner invia il piano di esecuzione a un server radice che coordina l'esecuzione della query ed esegue la distribuzione remota dei sottopiani.
Questo piano di esecuzione inizia con un unione distribuita, che distribuisce
ai server remoti le cui suddivisioni soddisfano SingerId < 100
. Dopo la scansione
sui singoli completamenti, l'operatore stream aggregato aggrega le righe
per ottenere il conteggio per ogni SingerId
. L'operatore serializza il risultato quindi
serializza il risultato. Infine, l'unione distribuita combina tutti i risultati
e restituisce i risultati della query.
Per scoprire di più sui dati aggregati, consulta la pagina aggregate operator.
Query di join nello stesso luogo
Le tabelle interlealate sono archiviate fisicamente con le relative righe di tabelle correlate con sede condivisa. Un unione con sede condivisa è un join tra tabelle con interleaving. Con sede condivisa i join possono offrire vantaggi in termini di prestazioni rispetto a quelli che richiedono indici o Indietro .
Ad esempio, utilizzando questa query:
SELECT al.AlbumTitle, so.SongName
FROM Albums AS al, Songs AS so
WHERE al.SingerId = so.SingerId AND al.AlbumId = so.AlbumId;
Questa query presuppone che Songs
sia con interleaving in Albums
.
Ecco i risultati:
+-----------------------+--------------------------+
| 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 |
+-----------------------+--------------------------+
Questo è il piano di esecuzione:
Questo piano di esecuzione inizia con un unione distribuita, che
distribuisce i sottopiani ai server remoti che hanno suddivisioni della tabella Albums
.
Poiché Songs
è una tabella con interleaving di Albums
, ogni server remoto può
eseguire l'intero sottopiano su ciascun server remoto senza richiedere un join
a un altro server.
I sottopiani contengono un'opzione cross apply. Ogni applicazione incrociata esegue una tabella
scan nella tabella Albums
per recuperare SingerId
, AlbumId
e
AlbumTitle
. L'opzione Cross apply mappa quindi l'output dalla scansione della tabella all'output
da una scansione dell'indice sull'indice SongsBySingerAlbumSongNameDesc
, soggetto a un
filtro del SingerId
nell'indice corrispondente al SingerId
del
output della scansione della tabella. Ogni applicazione incrociata invia i risultati a un risultato in serie
operatore che serializza i dati AlbumTitle
e SongName
e restituisce
i risultati ai sindacati distribuiti locali. I dati aggregati dell'unione distribuita
i risultati dalle unioni distribuite locali e li restituisce come risultato della query.
Query di indice e di back join
L'esempio precedente utilizzava un join su due tabelle, una con interleaving nell'altra. I piani di esecuzione sono più complessi e meno efficienti quando si utilizzano due tabelle o una sola tabella e un indice, non sono interleali.
Considera un indice creato con il comando seguente:
CREATE INDEX SongsBySongName ON Songs(SongName)
Usa questo indice in questa query:
SELECT s.SongName, s.Duration
FROM Songs@{force_index=SongsBySongName} AS s
WHERE STARTS_WITH(s.SongName, "B");
Ecco i risultati:
+----------+----------+
| SongName | Duration |
+----------+----------+
| Blue | 238 |
+----------+----------+
Questo è il piano di esecuzione:
Il piano di esecuzione risultante è complicato perché l'indice SongsBySongName
non contiene la colonna Duration
. Per ottenere il valore Duration
,
Spanner deve eseguire il back join dei risultati indicizzati nella tabella
Songs
. Questo è un join ma non è posizionato contemporaneamente perché la tabella Songs
e
l'indice globale SongsBySongName
non è con interleaving. L'esecuzione risultante
è più complesso dell'esempio di join con posizione condivisa perché
Spanner esegue ottimizzazioni per accelerare l'esecuzione se i dati
non viene localizzato.
L'operatore principale è un applicazione incrociata distribuita. Questo lato di input
questo operatore sono batch di righe dell'indice SongsBySongName
che soddisfano
il predicato STARTS_WITH(s.SongName, "B")
. L'opzione Distributed Cross apply
quindi mappa questi batch a server remoti le cui suddivisioni contengono il parametro Duration
e i dati di Google Cloud. I server remoti utilizzano una scansione delle tabelle per recuperare la colonna Duration
.
La scansione della tabella utilizza il filtro Condition:($Songs_key_TrackId' =
$batched_Songs_key_TrackId)
, che unisce TrackId
dalla tabella Songs
a
TrackId
delle righe raggruppate dall'indice SongsBySongName
.
I risultati vengono aggregati nella risposta finale della query. A sua volta, il lato di input
di un'applicazione incrociata distribuita contiene un'istanza
distribuita in un'istanza
di unione per valutare le righe dell'indice che soddisfano STARTS_WITH
predicato.
Considera una query leggermente diversa che non seleziona la colonna s.Duration
:
SELECT s.SongName
FROM Songs@{force_index=SongsBySongName} AS s
WHERE STARTS_WITH(s.SongName, "B");
Questa query è in grado di sfruttare appieno l'indice come mostrato in questo piano di esecuzione:
Il piano di esecuzione non richiede un back join perché tutte le colonne richieste dalla query sono presenti nell'indice.
Passaggi successivi
Scopri di più sugli operatori di esecuzione delle query
Scopri di più sullo strumento di ottimizzazione delle query di Spanner
Scopri come gestire lo strumento per ottimizzare le query