In un database Spanner, Spanner crea automaticamente un indice per la chiave primaria di ogni tabella. Ad esempio, non devi fare nulla per indicizzare la chiave primaria di Singers
, perché viene indicizzata automaticamente.
Puoi anche creare indici secondari per altre colonne. L'aggiunta di un indice secondario a una colonna rende più efficiente la ricerca dei dati nella colonna. Ad esempio, se devi cercare rapidamente un album per titolo, devi creare un indice secondario su AlbumTitle
, in modo che Spanner non debba analizzare l'intera tabella.
Se la ricerca nell'esempio precedente viene eseguita all'interno di una transazione di lettura/scrittura, la ricerca più efficiente evita anche di bloccare blocchi sull'intera tabella, il che consente l'inserimento e gli aggiornamenti simultanei della tabella per le righe esterne all'intervallo di ricerca AlbumTitle
.
Oltre ai vantaggi che apportano alle ricerche, gli indici secondari possono anche aiutare Spanner a eseguire scansioni in modo più efficiente, abilitando le scansioni degli indici anziché le analisi di tabelle complete.
Spanner archivia i seguenti dati in ogni indice secondario:
- Tutte le colonne chiave della tabella di base
- Tutte le colonne incluse nell'indice
- Tutte le colonne specificate nella clausola facoltativa
STORING
(database di dialetto GoogleSQL) oINCLUDE
(database di dialetto PostgreSQL) della definizione dell'indice.
Nel tempo, Spanner analizza le tabelle per garantire che gli indici secondari vengano utilizzati per le query appropriate.
Aggiungi un indice secondario
Il momento più efficiente per aggiungere un indice secondario è quando crei la tabella. Per creare contemporaneamente una tabella e i relativi indici, invia a Spanner le istruzioni DDL per la nuova tabella e i nuovi indici in una singola richiesta.
In Spanner, puoi anche aggiungere un nuovo indice secondario a una tabella esistente mentre il database continua a gestire il traffico. Come per qualsiasi altra modifica allo schema in Spanner, l'aggiunta di un indice a un database esistente non richiede di mettere offline il database e non blocca intere colonne o tabelle.
Ogni volta che viene aggiunto un nuovo indice a una tabella esistente, Spanner esegue automaticamente il backfill, o lo completa, in modo da riflettere una visualizzazione aggiornata dei dati indicizzati. Spanner gestisce per te questo processo di backfill, che viene eseguito in background utilizzando risorse dei nodi a priorità bassa. Nella maggior parte dei casi non è possibile accelerare il processo (ad esempio, aggiungendo più nodi) e il backfill non influisce in modo significativo sulle prestazioni del database.
La creazione dell'indice può richiedere da diversi minuti a molte ore. Poiché la creazione dell'indice è un aggiornamento dello schema, è vincolata dagli stessi vincoli di prestazioni di qualsiasi altro aggiornamento dello schema. Il tempo necessario per creare un indice secondario dipende da diversi fattori:
- La dimensione del set di dati
- La capacità di calcolo dell'istanza
- Il carico sull'istanza
Per visualizzare l'avanzamento di un processo di backfill dell'indice, consulta la sezione di avanzamento.
Tieni presente che l'utilizzo della colonna del timestamp del commit come prima parte dell'indice secondario può creare hotspot e ridurre le prestazioni di scrittura.
Utilizza l'istruzione CREATE INDEX
per definire un indice secondario nello schema. Ecco alcuni esempi:
Per indicizzare tutti i Singers
del database in base al nome e al cognome:
GoogleSQL
CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName);
PostgreSQL
CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName);
Per creare un indice di tutti i valori Songs
nel database in base al valore di SongName
:
GoogleSQL
CREATE INDEX SongsBySongName ON Songs(SongName);
PostgreSQL
CREATE INDEX SongsBySongName ON Songs(SongName);
Per indicizzare solo i brani di un determinato cantante, utilizza la clausola INTERLEAVE IN
per interfogliare l'indice nella tabella Singers
:
GoogleSQL
CREATE INDEX SongsBySingerSongName ON Songs(SingerId, SongName),
INTERLEAVE IN Singers;
PostgreSQL
CREATE INDEX SongsBySingerSongName ON Songs(SingerId, SongName)
INTERLEAVE IN Singers;
Per indicizzare solo i brani di un album specifico:
GoogleSQL
CREATE INDEX SongsBySingerAlbumSongName ON Songs(SingerId, AlbumId, SongName),
INTERLEAVE IN Albums;
PostgreSQL
CREATE INDEX SongsBySingerAlbumSongName ON Songs(SingerId, AlbumId, SongName)
INTERLEAVE IN Albums;
Per indicizzare in ordine decrescente in base a SongName
:
GoogleSQL
CREATE INDEX SongsBySingerAlbumSongNameDesc ON Songs(SingerId, AlbumId, SongName DESC),
INTERLEAVE IN Albums;
PostgreSQL
CREATE INDEX SongsBySingerAlbumSongNameDesc ON Songs(SingerId, AlbumId, SongName DESC)
INTERLEAVE IN Albums;
Tieni presente che l'annotazione DESC
sopra si applica solo a SongName
. Per indicizzare in ordine decrescente le altre chiavi di indice, annota anche queste con DESC
: SingerId DESC, AlbumId DESC
.
Tieni inoltre presente che PRIMARY_KEY
è una parola riservata e non può essere utilizzata come nome di un indice. È il nome assegnato allo pseudo-indice quando viene creata una tabella con specifica della CHIAVE PRINCIPALE
Per ulteriori dettagli e best practice per la scelta degli indici senza interleaving e degli indici con interleaving, consulta Opzioni di indice e Utilizzare un indice con interleaving su una colonna il cui valore aumenta o diminuisce monotonicamente.
Controlla l'avanzamento del backfill dell'indice
Console
Nel menu di navigazione di Spanner, fai clic sulla scheda Operazioni. La pagina Operazioni mostra un elenco delle operazioni attualmente in esecuzione.
Trova l'operazione di backfill nell'elenco. Se è ancora in esecuzione, l'indicatore di avanzamento nella colonna Ora di fine mostra la percentuale dell'operazione completata, come mostrato nella seguente immagine:
gcloud
Utilizza gcloud spanner operations describe
per verificare l'avanzamento di un'operazione.
Recupera l'ID operazione:
gcloud spanner operations list --instance=INSTANCE-NAME \ --database=DATABASE-NAME --type=DATABASE_UPDATE_DDL
Sostituisci quanto segue:
- INSTANCE-NAME con il nome dell'istanza Spanner.
- DATABASE-NAME con il nome del database.
Note sull'utilizzo:
Per limitare l'elenco, specifica il flag
--filter
. Ad esempio:--filter="metadata.name:example-db"
elenca solo le operazioni su un database specifico.- In
--filter="error:*"
sono elencate solo le operazioni di backup non riuscite.
Per informazioni sulla sintassi dei filtri, consulta la pagina relativa ai filtri degli argomenti gcloud. Per informazioni su come filtrare le operazioni di backup, consulta il campo
filter
in ListBackupOperationsRequest.Il flag
--type
non è sensibile alle maiuscole.
L'output è simile al seguente:
OPERATION_ID STATEMENTS DONE @TYPE _auto_op_123456 CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName) False UpdateDatabaseDdlMetadata CREATE INDEX SongsBySingerAlbumSongName ON Songs(SingerId, AlbumId, SongName), INTERLEAVE IN Albums _auto_op_234567 True CreateDatabaseMetadata
Esegui
gcloud spanner operations describe
:gcloud spanner operations describe \ --instance=INSTANCE-NAME \ --database=DATABASE-NAME \ projects/PROJECT-NAME/instances/INSTANCE-NAME/databases/DATABASE-NAME/operations/OPERATION_ID
Sostituisci quanto segue:
- INSTANCE-NAME: nome dell'istanza Spanner.
- DATABASE-NAME: il nome del database Spanner.
- PROJECT-NAME: il nome del progetto.
- OPERATION-ID: l'ID dell'operazione che vuoi controllare.
La sezione
progress
nell'output mostra la percentuale dell'operazione completata. L'output è simile al seguente:done: true ... progress: - endTime: '2021-01-22T21:58:42.912540Z' progressPercent: 100 startTime: '2021-01-22T21:58:11.053996Z' - progressPercent: 67 startTime: '2021-01-22T21:58:11.053996Z' ...
REST v1
Recupera l'ID operazione:
gcloud spanner operations list --instance=INSTANCE-NAME
--database=DATABASE-NAME --type=DATABASE_UPDATE_DDL
Sostituisci quanto segue:
- INSTANCE-NAME con il nome dell'istanza Spanner.
- DATABASE-NAME con il nome del database.
Prima di utilizzare i dati della richiesta, effettua le seguenti sostituzioni:
- project-id: l'ID progetto.
- instance-id: l'ID istanza.
- database-id: l'ID del database.
- operation-id: l'ID operazione.
Metodo HTTP e URL:
GET https://spanner.googleapis.com/v1/projects/project-id/instances/instance-id/databases/database-id/operations/operation-id
Per inviare la richiesta, espandi una di queste opzioni:
Dovresti ricevere una risposta JSON simile alla seguente:
{ ... "progress": [ { "progressPercent": 100, "startTime": "2023-05-27T00:52:27.366688Z", "endTime": "2023-05-27T00:52:30.184845Z" }, { "progressPercent": 100, "startTime": "2023-05-27T00:52:30.184845Z", "endTime": "2023-05-27T00:52:40.750959Z" } ], ... "done": true, "response": { "@type": "type.googleapis.com/google.protobuf.Empty" } }
Per gcloud
e REST, puoi trovare l'avanzamento di ogni istruzione di backfill dell'indice nella sezione progress
. A ogni istruzione dell'array di istruzioni è presente un
campo corrispondente nell'array progress. Questo ordine dell'array di avanzamento corrisponde all'ordine dell'array delle istruzioni. Una volta disponibili, i campi startTime
, progressPercent
e endTime
vengono compilati di conseguenza.
Tieni presente che l'output non mostra una stima del tempo necessario per il completamento
dell'avanzamento del backfill.
Se l'operazione richiede troppo tempo, puoi annullarla. Per maggiori informazioni, consulta Annullare la creazione dell'indice.
Scenari durante la visualizzazione dell'avanzamento del backfill dell'indice
Quando provi a verificare l'avanzamento di un backfill dell'indice, puoi riscontrare diversi scenari. Le istruzioni di creazione dell'indice che richiedono un backfill dell'indice fanno parte delle operazioni di aggiornamento dello schema e possono esserci diverse istruzioni parte di un'operazione di aggiornamento dello schema.
Il primo scenario è il più semplice, ovvero quando l'istruzione di creazione dell'indice è la prima istruzione nell'operazione di aggiornamento dello schema. Poiché l'istruzione di creazione dell'indice è la prima istruzione, è la prima elaborata ed eseguita a causa dell'ordine di esecuzione.
Immediatamente, il campo startTime
dell'istruzione di creazione dell'indice verrà completato con l'ora di inizio dell'operazione di aggiornamento dello schema. Il campo progressPercent
dell'istruzione di creazione dell'indice viene quindi compilato quando l'avanzamento del backfill dell'indice è superiore allo 0%. Infine, il campo endTime
viene compilato una volta eseguito il commit dell'istruzione.
Il secondo scenario si verifica quando l'istruzione di creazione dell'indice non è la prima
istruzione nell'operazione di aggiornamento dello schema. Nessun campo relativo all'istruzione di creazione dell'indice verrà completato finché non viene eseguito il commit delle istruzioni precedenti a causa dell'ordine di esecuzione.
Analogamente allo scenario precedente, una volta eseguito il commit delle istruzioni precedenti, viene completato per primo il campo startTime
dell'istruzione di creazione dell'indice, seguito dal campo progressPercent
. Infine, il campo endTime
viene completato una volta completato il commit dell'istruzione.
Annulla creazione indice
Puoi utilizzare Google Cloud CLI per annullare la creazione dell'indice. Per recuperare un elenco di operazioni di aggiornamento dello schema per un database Spanner, utilizza il comando gcloud spanner operations list
e includi l'opzione --filter
:
gcloud spanner operations list \
--instance=INSTANCE \
--database=DATABASE \
--filter="@TYPE:UpdateDatabaseDdlMetadata"
Trova il OPERATION_ID
per l'operazione che vuoi annullare, quindi utilizza il comando gcloud spanner operations cancel
per annullarla:
gcloud spanner operations cancel OPERATION_ID \
--instance=INSTANCE \
--database=DATABASE
Visualizza indici esistenti
Per visualizzare le informazioni sugli indici esistenti in un database, puoi utilizzare la console Google Cloud o Google Cloud CLI:
Console
Vai alla pagina Istanze di Spanner nella console Google Cloud.
Fai clic sul nome dell'istanza che vuoi visualizzare.
Nel riquadro a sinistra, fai clic sul database da visualizzare, quindi sulla tabella che vuoi visualizzare.
Fai clic sulla scheda Indici. La console Google Cloud mostra un elenco di indici.
(Facoltativo) Per ottenere i dettagli di un indice, come le colonne che include, fai clic sul nome dell'indice.
gcloud
Usa il comando gcloud spanner databases ddl describe
:
gcloud spanner databases ddl describe DATABASE \
--instance=INSTANCE
L'interfaccia alla gcloud CLI stampa le istruzioni Data Definition Language (DDL) per creare le tabelle e gli indici del database. Le istruzioni CREATE
INDEX
descrivono gli indici esistenti. Ad
esempio:
--- |-
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX),
) PRIMARY KEY(SingerId)
---
CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName)
Query con un indice specifico
Le sezioni seguenti spiegano come specificare un indice in un'istruzione SQL e con l'interfaccia di lettura per Spanner. Negli esempi in queste sezioni si presuppone che tu abbia aggiunto una colonna MarketingBudget
alla tabella Albums
e creato un indice denominato AlbumsByAlbumTitle
:
GoogleSQL
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);
PostgreSQL
CREATE TABLE Albums (
SingerId BIGINT NOT NULL,
AlbumId BIGINT NOT NULL,
AlbumTitle VARCHAR,
MarketingBudget BIGINT,
PRIMARY KEY (SingerId, AlbumId)
) INTERLEAVE IN PARENT Singers ON DELETE CASCADE;
CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);
Specifica un indice in un'istruzione SQL
Quando esegui query su una tabella Spanner con SQL, Spanner utilizza automaticamente tutti gli indici che potrebbero rendere la query più efficiente. Di conseguenza, non è necessario specificare un indice per le query SQL. Tuttavia, per le query critiche per il tuo carico di lavoro, Google consiglia di utilizzare le istruzioni FORCE_INDEX
nelle istruzioni SQL per ottenere prestazioni più coerenti.
In alcuni casi, Spanner potrebbe scegliere un indice che causa l'aumento della latenza delle query. Se hai seguito la procedura di risoluzione dei problemi relativi alle regressioni delle prestazioni e hai verificato che ha senso provare un indice diverso per la query, puoi specificare l'indice come parte della query.
Per specificare un indice in un'istruzione SQL, utilizza il suggerimento FORCE_INDEX
per fornire un'istruzione di indice. La sintassi delle istruzioni di indice è la seguente:
GoogleSQL
FROM MyTable@{FORCE_INDEX=MyTableIndex}
PostgreSQL
FROM MyTable /*@ FORCE_INDEX = MyTableIndex */
Puoi anche utilizzare un'istruzione di indice per indicare a Spanner di eseguire la scansione della tabella di base anziché utilizzare un indice:
GoogleSQL
FROM MyTable@{FORCE_INDEX=_BASE_TABLE}
PostgreSQL
FROM MyTable /*@ FORCE_INDEX = _BASE_TABLE */
L'esempio seguente mostra una query SQL che specifica un indice:
GoogleSQL
SELECT AlbumId, AlbumTitle, MarketingBudget
FROM Albums@{FORCE_INDEX=AlbumsByAlbumTitle}
WHERE AlbumTitle >= "Aardvark" AND AlbumTitle < "Goo";
PostgreSQL
SELECT AlbumId, AlbumTitle, MarketingBudget
FROM Albums /*@ FORCE_INDEX = AlbumsByAlbumTitle */
WHERE AlbumTitle >= 'Aardvark' AND AlbumTitle < 'Goo';
Una istruzione di indice potrebbe forzare il processore di query di Spanner a leggere le colonne aggiuntive richieste dalla query, ma non archiviate nell'indice.
Il processore di query recupera queste colonne unendo l'indice e la tabella di base. Per evitare questo join aggiuntivo, usa una clausola STORING
(database dialetti GoogleSQL) o INCLUDE
(database dialetto PostgreSQL) per archiviare le colonne aggiuntive nell'indice.
Ad esempio, nell'esempio mostrato sopra, la colonna MarketingBudget
non è archiviata nell'indice, ma la query SQL seleziona questa colonna. Di conseguenza,
Spanner deve cercare la colonna MarketingBudget
nella tabella di base, quindi unirla ai dati dell'indice per restituire i risultati della query.
Spanner genera un errore se l'istruzione di indice presenta uno dei seguenti problemi:
- L'indice non esiste.
- L'indice si trova su una tabella di base diversa.
- Nella query manca un'espressione di filtro
NULL
obbligatoria per un indiceNULL_FILTERED
.
I seguenti esempi mostrano come scrivere ed eseguire query che recuperano i valori di AlbumId
, AlbumTitle
e MarketingBudget
utilizzando l'indice AlbumsByAlbumTitle
:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Specifica un indice nell'interfaccia di lettura
Quando utilizzi l'interfaccia di lettura di Spanner e vuoi che Spanner utilizzi un indice, devi specificare l'indice. L'interfaccia di lettura non seleziona l'indice automaticamente.
Inoltre, l'indice deve contenere tutti i dati che vengono visualizzati nei risultati della query, escluse le colonne che fanno parte della chiave primaria. Questa limitazione esiste perché l'interfaccia di lettura non supporta i join tra l'indice e la tabella di base. Se devi includere altre colonne nei risultati della query, hai alcune opzioni a disposizione:
- Utilizza una clausola
STORING
oINCLUDE
per archiviare le colonne aggiuntive nell'indice. - Esegui una query senza includere le colonne aggiuntive, quindi utilizza le chiavi primarie per inviare un'altra query che legga le colonne aggiuntive.
Spanner restituisce i valori dall'indice in ordine crescente in base alla chiave di indice. Per recuperare i valori in ordine decrescente:
Annota la chiave di indice con
DESC
. Ad esempio:CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle DESC);
L'annotazione
DESC
si applica a una singola chiave di indice. Se l'indice include più di una chiave e vuoi che i risultati della query vengano visualizzati in ordine decrescente in base a tutte le chiavi, includi un'annotazioneDESC
per ogni chiave.Se la lettura specifica un intervallo di chiavi, assicurati che anche l'intervallo di chiavi sia in ordine decrescente. In altre parole, il valore della chiave iniziale deve essere maggiore del valore della chiave finale.
L'esempio seguente mostra come recuperare i valori di AlbumId
e AlbumTitle
utilizzando l'indice AlbumsByAlbumTitle
:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Crea un indice per le analisi solo dell'indice
Facoltativamente, puoi utilizzare la clausola STORING
(per i database dialetti SQL) o la clausola INCLUDE
(per i database dialetto PostgreSQL) per archiviare una copia di una colonna nell'indice. Questo tipo di indice offre vantaggi per le query e le chiamate di lettura che utilizzano l'indice, al costo di utilizzare spazio di archiviazione aggiuntivo:
- Le query SQL che utilizzano l'indice e selezionano le colonne archiviate nella clausola
STORING
oINCLUDE
non richiedono un join aggiuntivo alla tabella di base. - Le chiamate
read()
che utilizzano l'indice possono leggere le colonne archiviate dalla clausolaSTORING
/INCLUDE
.
Ad esempio, supponi di aver creato una versione alternativa di AlbumsByAlbumTitle
che archivia una copia della colonna MarketingBudget
nell'indice (nota la clausola
STORING
o INCLUDE
in grassetto):
GoogleSQL
CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget);
PostgreSQL
CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) INCLUDE (MarketingBudget);
Con il precedente indice AlbumsByAlbumTitle
, Spanner deve unire l'indice alla tabella di base e poi recuperare la colonna dalla tabella di base. Con il nuovo indice AlbumsByAlbumTitle2
, Spanner legge la colonna direttamente dall'indice, il che è più efficiente.
Se utilizzi l'interfaccia di lettura anziché SQL, il nuovo indice AlbumsByAlbumTitle2
ti consente anche di leggere direttamente la colonna MarketingBudget
:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Modificare un indice
Puoi utilizzare l'istruzione ALTER INDEX
per aggiungere ulteriori colonne
a un indice esistente o trascinarle. Questa operazione può aggiornare l'elenco di colonne definito dalla clausola STORING
(database dialetto GoogleSQL) o INCLUDE
(database dialetto PostgreSQL) quando crei l'indice. Non puoi utilizzare questa istruzione per aggiungere o eliminare colonne dalla chiave di indice. Ad esempio, anziché creare un nuovo indice AlbumsByAlbumTitle2
, puoi utilizzare ALTER INDEX
per aggiungere una colonna in AlbumsByAlbumTitle
, come mostrato nell'esempio seguente:
GoogleSQL
ALTER INDEX AlbumsByAlbumTitle ADD STORED COLUMN MarketingBudget
PostgreSQL
ALTER INDEX AlbumsByAlbumTitle ADD INCLUDE COLUMN MarketingBudget
Quando aggiungi una nuova colonna a un indice esistente, Spanner utilizza un processo di backfill in background. Mentre il backfill è in corso, la colonna nell'indice non è leggibile, quindi potresti non ottenere il miglioramento delle prestazioni previsto. Puoi utilizzare il comando gcloud spanner operations
per elencare l'operazione a lunga esecuzione e visualizzarne lo stato.
Per maggiori informazioni, vedi Descrivi l'operazione.
Puoi anche utilizzare l'operazione di annullamento per annullare un'operazione in esecuzione.
Al termine del backfill, Spanner aggiunge la colonna all'indice. Man mano che l'indice aumenta, ciò potrebbe rallentare le query che utilizzano l'indice.
L'esempio seguente mostra come eliminare una colonna da un indice:
GoogleSQL
ALTER INDEX AlbumsByAlbumTitle DROP STORED COLUMN MarketingBudget
PostgreSQL
ALTER INDEX AlbumsByAlbumTitle DROP INCLUDE COLUMN MarketingBudget
Indice dei valori NULL
Per impostazione predefinita, Spanner indicizza i valori NULL
. Ad esempio, richiama la definizione dell'indice SingersByFirstLastName
nella tabella Singers
:
CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName);
Tutte le righe di Singers
sono indicizzate anche se FirstName
, LastName
o
entrambi sono NULL
.
Quando i valori NULL
vengono indicizzati, puoi eseguire query SQL efficienti e leggere
i dati che includono i valori NULL
. Ad esempio, utilizza questa istruzione di query SQL
per trovare tutti i valori Singers
con un NULL
FirstName
:
GoogleSQL
SELECT s.SingerId, s.FirstName, s.LastName
FROM Singers@{FORCE_INDEX=SingersByFirstLastName} AS s
WHERE s.FirstName IS NULL;
PostgreSQL
SELECT s.SingerId, s.FirstName, s.LastName
FROM Singers /* @ FORCE_INDEX = SingersByFirstLastName */ AS s
WHERE s.FirstName IS NULL;
Ordinamento per valori NULL
Spanner ordina NULL
come il valore più piccolo per un determinato tipo. Per una
colonna in ordine crescente (ASC
), i valori NULL
vengono ordinati per primi. Per una colonna in
ordine decrescente (DESC
), i valori NULL
vengono ordinati per ultimi.
Disabilita l'indicizzazione dei valori NULL
GoogleSQL
Per disabilitare l'indicizzazione dei valori null, aggiungi la parola chiave NULL_FILTERED
alla definizione dell'indice. Gli indici NULL_FILTERED
sono particolarmente utili per l'indicizzazione delle colonne sparse, in cui la maggior parte delle righe contiene un valore NULL
. In questi casi, l'indice NULL_FILTERED
può essere notevolmente più piccolo ed efficiente da mantenere rispetto a un indice normale che include valori NULL
.
Ecco una definizione alternativa di SingersByFirstLastName
che non indicizza i valori NULL
:
CREATE NULL_FILTERED INDEX SingersByFirstLastNameNoNulls
ON Singers(FirstName, LastName);
La parola chiave NULL_FILTERED
si applica a tutte le colonne delle chiavi di indice. Non puoi specificare il filtro NULL
in base alla colonna.
PostgreSQL
Per filtrare le righe con valori nulli in una o più colonne indicizzate, utilizza il predicato WHERE COLUMN IS NOT NULL
.
Gli indici con filtro null sono particolarmente utili per l'indicizzazione di colonne sparse, in cui la maggior parte delle righe contiene un valore NULL
. In questi casi, l'indice con filtro null può essere notevolmente più piccolo e più efficiente da mantenere rispetto a un indice normale che include valori NULL
.
Ecco una definizione alternativa di SingersByFirstLastName
che non indicizza i valori NULL
:
CREATE INDEX SingersByFirstLastNameNoNulls
ON Singers(FirstName, LastName)
WHERE FirstName IS NOT NULL
AND LastName IS NOT NULL;
Se filtri i valori NULL
, Spanner non può utilizzarlo per alcune query. Ad esempio, Spanner non utilizza l'indice per questa query, perché l'indice omette qualsiasi riga Singers
per cui LastName
è NULL
; di conseguenza, l'utilizzo dell'indice impedirebbe alla query di restituire le righe corrette:
GoogleSQL
FROM Singers@{FORCE_INDEX=SingersByFirstLastNameNoNulls}
WHERE FirstName = "John";
PostgreSQL
FROM Singers /*@ FORCE_INDEX = SingersByFirstLastNameNoNulls */
WHERE FirstName = 'John';
Per consentire a Spanner di utilizzare l'indice, devi riscrivere la query in modo che escluda le righe che sono a loro volta escluse dall'indice:
GoogleSQL
SELECT FirstName, LastName
FROM Singers@{FORCE_INDEX=SingersByFirstLastNameNoNulls}
WHERE FirstName = 'John' AND LastName IS NOT NULL;
PostgreSQL
SELECT FirstName, LastName
FROM Singers /*@ FORCE_INDEX = SingersByFirstLastNameNoNulls */
WHERE FirstName = 'John' AND LastName IS NOT NULL;
Indici univoci
Gli indici possono essere dichiarati UNIQUE
. Gli indici UNIQUE
aggiungono un vincolo ai dati indicizzati che impedisce voci duplicate per una determinata chiave di indice.
Questo vincolo viene applicato da Spanner al momento del commit della transazione.
In particolare, non verrà eseguito il commit di qualsiasi transazione che comporterebbe l'esistenza di più voci di indice per la stessa chiave.
Se all'inizio una tabella contiene dati non UNIQUE
, il tentativo di creare un indice UNIQUE
al suo interno non andrà a buon fine.
Una nota sugli indici UNIQUE NULL_FILTERED
Un indice UNIQUE NULL_FILTERED
non applica l'unicità della chiave di indice quando almeno una delle parti chiave dell'indice è NULL.
Ad esempio, supponi di aver creato la tabella e l'indice seguenti:
GoogleSQL
CREATE TABLE ExampleTable (
Key1 INT64 NOT NULL,
Key2 INT64,
Key3 INT64,
Col1 INT64,
) PRIMARY KEY (Key1, Key2, Key3);
CREATE UNIQUE NULL_FILTERED INDEX ExampleIndex ON ExampleTable (Key1, Key2, Col1);
PostgreSQL
CREATE TABLE ExampleTable (
Key1 BIGINT NOT NULL,
Key2 BIGINT,
Key3 BIGINT,
Col1 BIGINT,
PRIMARY KEY (Key1, Key2, Key3)
);
CREATE UNIQUE INDEX ExampleIndex ON ExampleTable (Key1, Key2, Col1)
WHERE Key1 IS NOT NULL
AND Key2 IS NOT NULL
AND Col1 IS NOT NULL;
Le seguenti due righe in ExampleTable
hanno gli stessi valori per le chiavi di indice secondarie Key1
, Key2
e Col1
:
1, NULL, 1, 1
1, NULL, 2, 1
Poiché Key2
è NULL
e l'indice è filtrato da null, le righe non saranno
presenti nell'indice ExampleIndex
. Poiché non sono inseriti nell'indice, l'indice non li rifiuterà per violazione dell'unicità su (Key1, Key2,
Col1)
.
Se vuoi che l'indice applichi l'unicità dei valori della tupla (Key1
, Key2
, Col1
), devi annotare Key2
con NOT NULL
nella definizione della tabella o creare l'indice senza filtrare i valori null.
Elimina un indice
Utilizza l'istruzione DROP INDEX
per eliminare un indice secondario dallo schema.
Per eliminare l'indice denominato SingersByFirstLastName
:
DROP INDEX SingersByFirstLastName;
Indice per una scansione più rapida
Quando Spanner deve eseguire una scansione della tabella (anziché una ricerca indicizzata) per recuperare i valori da una o più colonne, puoi ricevere risultati più rapidi se esiste un indice per quelle colonne e nell'ordine specificato dalla query. Se esegui spesso query che richiedono scansioni, valuta la possibilità di creare indici secondari per consentire queste scansioni in modo più efficiente.
In particolare, se hai bisogno che Spanner esegua spesso la scansione della chiave primaria o di un altro indice di una tabella in ordine inverso, puoi aumentarne l'efficienza tramite un indice secondario che renda esplicito l'ordine desiderato.
Ad esempio, la query seguente restituisce sempre un risultato veloce, anche se
Spanner deve analizzare Songs
per trovare il valore più basso di
SongId
:
SELECT SongId FROM Songs LIMIT 1;
SongId
è la chiave primaria della tabella, archiviata (come per tutte le chiavi primarie)
in ordine crescente. Spanner può analizzare l'indice della chiave
e trovare rapidamente il primo risultato.
Tuttavia, senza l'aiuto di un indice secondario, la seguente query non verrebbe restituita così rapidamente, soprattutto se Songs
contiene molti dati:
SELECT SongId FROM Songs ORDER BY SongId DESC LIMIT 1;
Anche se SongId
è la chiave primaria della tabella, Spanner non ha modo di recuperare il valore più alto della colonna senza ricorrere a un'analisi completa della tabella.
L'aggiunta del seguente indice consentirebbe a questa query di restituire più rapidamente:
CREATE INDEX SongIdDesc On Songs(SongId DESC);
Una volta creato l'indice, Spanner lo avrebbe utilizzato per restituire un risultato per la seconda query molto più rapidamente.
Passaggi successivi
- Scopri le best practice per SQL per Spanner.
- Scopri i piani di esecuzione delle query per Spanner.
- Scopri come risolvere i problemi di regressione delle prestazioni nelle query SQL.