In questa pagina vengono descritti i concetti da considerare quando si seleziona Firestore in modalità Datastore per l'app.
Firestore in modalità Datastore offre prestazioni elevate delle query utilizzando gli indici per tutte le query. Le prestazioni della maggior parte delle query dipendono dalla dimensione del set di risultati e non dalla dimensione totale del database.
Firestore in modalità Datastore definisce gli indici integrati per ogni proprietà in un'entità. Questi indici di proprietà singole supportano molte query semplici. Firestore in modalità Datastore supporta una funzionalità di unione degli indici che consente al database di unire gli indici integrati per supportare query aggiuntive. Per query più complesse, è necessario definire in anticipo gli indici composti.
Questa pagina è incentrata sulla funzionalità di unione degli indici, perché influisce su due importanti opportunità di ottimizzazione dell'indice:
- Accelerazione delle query
- Ridurre il numero di indici composti
L'esempio seguente illustra la funzionalità di unione degli indici.
Filtro di Photo
entità in corso...
Considera un database in modalità Datastore con entità di tipo Photo
:
Foto | ||
---|---|---|
Proprietà | Tipo di valore | Descrizione |
owner_id |
Stringa | ID utente |
tag |
Array di stringhe | Parole chiave tokenizzate |
size |
Numero intero |
Enumerazione:
|
coloration |
Numero intero |
Enumerazione:
|
Immagina di aver bisogno di una funzionalità dell'app che consenta agli utenti di eseguire query su entità Photo
in base a un AND
logico dei seguenti elementi:
Fino a tre filtri in base alle proprietà:
owner_id
size
coloration
Una stringa di ricerca
tag
. L'app tokenizza la stringa di ricerca nei tag e aggiunge un filtro per ogni tag.Ad esempio, l'app trasforma la stringa di ricerca
outside, family
nei filtri di querytag=outside
etag=family
.
Utilizzando gli indici integrati e Firestore nella funzionalità di unione degli indici in modalità Datastore, puoi soddisfare i requisiti di indice di questa funzionalità di filtro Photo
senza aggiungere indici composti aggiuntivi.
Gli indici integrati per le entità Photo
supportano query con filtro singolo come:
Python
La funzionalità di filtro Photo
richiede anche query che combinano più filtri di uguaglianza con un AND
logico:
Python
Firestore in modalità Datastore può supportare queste query mediante l'unione degli indici integrati.
Unione indice
Firestore in modalità Datastore può utilizzare l'unione degli indici quando la query e gli indici soddisfano tutti i seguenti vincoli:
- La query utilizza solo filtri di uguaglianza (
=
) - Non esiste un indice composto che corrisponda perfettamente ai filtri e all'ordine della query
- Ogni filtro di uguaglianza corrisponde ad almeno un indice esistente con lo stesso ordine della query
In questo caso, Firestore in modalità Datastore può utilizzare gli indici esistenti per supportare la query anziché dover configurare un indice composto aggiuntivo.
Quando due o più indici vengono ordinati in base agli stessi criteri, Firestore in modalità Datastore può unire i risultati di più analisi degli indici per trovare risultati comuni a tutti questi indici. Firestore in modalità Datastore può unire gli indici integrati, perché ordinano tutti i valori per chiave di entità.
Unendo gli indici integrati, Firestore in modalità Datastore supporta query con filtri di uguaglianza su più proprietà:
Python
Firestore in modalità Datastore può anche unire i risultati dell'indice da più sezioni dello stesso indice. Unendo diverse sezioni dell'indice integrato per la proprietà tag
, Firestore in modalità Datastore supporta le query che combinano più filtri tag
in un AND
logico:
Python
Le query supportate dagli indici integrati uniti completano l'insieme di query richiesto dalla funzionalità di filtro Photo
. Tieni presente che il supporto della funzionalità di filtro Photo
non richiedeva indici composti aggiuntivi.
Quando selezioni gli indici ottimali per la tua app, è importante comprendere la funzionalità di unione degli indici. L'unione degli indici offre a Firestore in modalità Datastore una maggiore flessibilità nelle query, ma con un possibile compromesso sulle prestazioni. La sezione successiva descrive le prestazioni dell'unione degli indici e come migliorare le prestazioni aggiungendo indici composti.
Ricerca dell'indice perfetto
L'indice viene ordinato prima per predecessore e poi per valori delle proprietà, nell'ordine specificato nella definizione dell'indice. L'indice composto perfetto per una query, che consente un'esecuzione più efficiente della query, viene definito nelle seguenti proprietà, in ordine:
- Proprietà utilizzate nei filtri di uguaglianza
- Proprietà utilizzate negli ordini di ordinamento
- Proprietà utilizzate nel filtro
distinctOn
- Proprietà utilizzate nei filtri di intervallo e disuguaglianza (non ancora incluse negli ordini)
- Proprietà utilizzate in aggregazioni e proiezioni (non ancora incluse negli ordini di ordinamento e nei filtri di intervallo e disuguaglianza)
In questo modo verranno presi in considerazione tutti i risultati di ogni possibile esecuzione della query. I database Firestore in modalità Datastore eseguono una query utilizzando un indice perfetto seguendo questi passaggi:
- Identifica l'indice corrispondente al tipo, alle proprietà di filtro, agli operatori di filtro e agli ordini di ordinamento della query
- Esegue la scansione dall'inizio dell'indice alla prima entità che soddisfa tutte o un sottoinsieme delle condizioni di filtro della query
- Continua la scansione dell'indice, restituendo ogni entità che soddisfa tutte le condizioni di filtro, finché non viene
- rileva un'entità che non soddisfa le condizioni di filtro oppure
- raggiunge la fine dell'indice o
- ha raccolto il numero massimo di risultati richiesti dalla query
Ad esempio, considera la query seguente:
SELECT * FROM Task
WHERE category = 'Personal'
AND priority < 3
ORDER BY priority DESC
L'indice composto perfetto per questa query è un indice di chiavi per le entità di tipo Task
, con colonne per i valori delle proprietà category
e priority
. L'indice viene ordinato prima in ordine crescente in base a category
e poi in ordine decrescente in base a priority
:
indexes:
- kind: Task
properties:
- name: category
direction: asc
- name: priority
direction: desc
Due query dello stesso formato, ma con valori di filtro diversi, utilizzano lo stesso indice. Ad esempio, la query seguente utilizza lo stesso indice della query precedente:
SELECT * FROM Task
WHERE category = 'Work'
AND priority < 5
ORDER BY priority DESC
Per questo indice
indexes:
- kind: Task
properties:
- name: category
direction: asc
- name: priority
direction: asc
- name: created
direction: asc
L'indice precedente può soddisfare entrambe le seguenti query:
SELECT * FROM Task
WHERE category = 'Personal'
AND priority = 5
ORDER BY created ASC
e
SELECT * FROM Task
WHERE category = 'Work'
ORDER BY priority ASC, created ASC
Ottimizzazione della selezione degli indici
Questa sezione descrive le caratteristiche delle prestazioni dell'unione degli indici e due opportunità di ottimizzazione correlate all'unione:
- Aggiungi indici composti per velocizzare le query che si basano sugli indici uniti
- Riduci il numero di indici composti sfruttando gli indici uniti
Rendimento dell'unione degli indici
In un'unione di indici, Firestore in modalità Datastore unisce in modo efficiente gli indici utilizzando un algoritmo di join di unione a zig-zag. Utilizzando questo algoritmo, la modalità Datastore unisce le potenziali corrispondenze di più analisi dell'indice per produrre un set di risultati che corrisponde a una query. L'unione degli indici combina i componenti di filtro in fase di lettura anziché in fase di scrittura. A differenza della maggior parte delle query di Firestore in modalità Datastore, in cui le prestazioni dipendono solo dalla dimensione del set di risultati, le prestazioni delle query di unione dell'indice dipendono dai filtri nella query e dal numero di potenziali corrispondenze preso in considerazione dal database.
Le migliori prestazioni di un'unione di indici si verificano quando ogni potenziale corrispondenza in un indice soddisfa i filtri delle query. In questo caso, le prestazioni sono O(R * I)
, dove R
è la dimensione del set di risultati e I
è il numero di indici scansionati.
Le prestazioni peggiori si verificano quando il database deve considerare molte corrispondenze potenziali, ma poche di queste soddisfano i filtri delle query. In questo caso, le prestazioni sono O(S)
, dove S
è la dimensione del più piccolo insieme potenziale di entità provenienti da una singola scansione dell'indice.
Il rendimento effettivo dipende dalla forma dei dati. Il
numero medio di entità considerate per ogni risultato restituito è
O(S/(R * I))
. Le query hanno un rendimento peggiore quando molte entità corrispondono a ogni analisi dell'indice, ma poche entità corrispondono alla query nel suo complesso, il che significa che R
è piccolo e S
è grande.
Questo rischio è attenuato da quattro fattori:
Lo strumento di pianificazione delle query non cerca un'entità finché non ha verificato che l'entità corrisponde all'intera query.
L'algoritmo a zig-zag non ha bisogno di trovare tutti i risultati per restituire il risultato successivo. Se richiedi i primi 10 risultati, paghi solo la latenza per trovare quei 10 risultati.
L'algoritmo a zig-zag ignora ampie sezioni di risultati falsi positivi. Le prestazioni peggiori si verificano solo se i risultati falsi positivi sono perfettamente intrecciati (in ordine) tra le scansioni.
La latenza dipende dal numero di entità trovate in ogni scansione dell'indice, non dal numero di entità corrispondenti a ciascun filtro. Come mostrato nella prossima sezione, puoi aggiungere indici composti per migliorare le prestazioni dell'unione degli indici.
Accelerare una query di unione dell'indice
Quando Firestore in modalità Datastore unisce gli indici, ogni analisi dell'indice spesso è mappata a un singolo filtro nella query. Puoi migliorare le prestazioni delle query aggiungendo indici composti che corrispondono a più filtri nella query.
Considera questa query:
Python
Ogni filtro è mappato a una scansione dell'indice nei seguenti indici integrati:
Index(Photo, owner_id) Index(Photo, size) Index(Photo, tag)
Se aggiungi l'indice composto Index(Photo, owner_id, size)
, la query viene mappata a due analisi dell'indice anziché a tre:
# Satisfies both 'owner_id=username' and 'size=2' Index(Photo, owner_id, size) Index(Photo, tag)
Prendi in considerazione uno scenario con molte immagini di grandi dimensioni, molte immagini in bianco e nero e poche immagini grandi e panoramiche. Un filtro delle query per le immagini panoramiche e in bianco e nero sarà lento se unisce gli indici integrati:
Python
Per migliorare le prestazioni delle query, puoi ridurre il valore di S
(insieme più piccolo di entità in una singola scansione dell'indice) in O(S/(R * I))
aggiungendo il seguente indice composto:
Index(Photo, size, coloration)
Rispetto all'utilizzo di due indici integrati, questo indice composto produce meno risultati potenziali per gli stessi due filtri di query. Questo approccio migliora sostanzialmente il rendimento a fronte di un altro indice.
Riduzione del numero di indici composti con l'unione degli indici
Anche se gli indici composti che corrispondono esattamente ai filtri di una query funzionano meglio, non è sempre migliore o possibile aggiungere un indice composto per ogni combinazione di filtri. Devi bilanciare gli indici composti con quanto segue:
Limiti dell'indice composto:
Limite Importo Numero massimo di indici composti per un database -
200 se non hai abilitato la fatturazione per il tuo progetto Google Cloud.
Se hai bisogno di quote superiori, devi abilitare la fatturazione per il tuo progetto Google Cloud.
-
500 quando abiliti la fatturazione per il tuo progetto Google Cloud.
Puoi contattare l'assistenza per richiedere un aumento di questo limite.
Somma massima delle dimensioni delle voci dell'indice composto di un'entità 2 MiB Somma massima dei seguenti elementi per un'entità: - numero di valori di proprietà indicizzati
- numero di voci dell'indice composto
20.000 -
- Costi di archiviazione di ogni indice aggiuntivo.
- Effetti sulla latenza di scrittura.
I problemi di indicizzazione spesso si verificano con campi multivalore come la proprietà tag
delle entità Photo
.
Ad esempio, immagina che la funzionalità di filtro Photo
ora debba supportare clausole di ordinamento decrescente in base a quattro proprietà aggiuntive:
Foto | ||
---|---|---|
Proprietà | Tipo di valore | Descrizione |
date_added |
Numero intero | Data/ora |
rating |
In virgola mobile | Valutazione complessiva degli utenti |
comment_count |
Numero intero | Numero di commenti |
download_count |
Numero intero | Numero di download |
Se ignori il campo tag
, puoi selezionare indici composti che corrispondono a ogni combinazione di filtri Photo
:
Index(Photo, owner_id, -date_added) Index(Photo, owner_id, -comments) Index(Photo, size, -date_added) Index(Photo, size, -comments) ... Index(Photo, owner_id, size, -date_added) Index(Photo, owner_id, size, -comments) ... Index(Photo, owner_id, size, coloration, -date_added) Index(Photo, owner_id, size, coloration, -comments)
Il numero totale di indici composti è:
2^(number of filters) * (number of different orders) = 2 ^ 3 * 4 = 32 composite indexes
Se provi a supportare fino a 3 filtri tag
, il numero totale di indici composti è:
2 ^ (3 + 3 tag filters) * 4 = 256 indexes.
Gli indici che includono proprietà multivalore come tag
causano anche problemi di indice che aumentano i costi di archiviazione e la latenza di scrittura.
Per supportare i filtri nel campo tag
per questa funzionalità, puoi ridurre il numero totale di indici utilizzando gli indici uniti. Il seguente set di indici composti
è il minimo richiesto per supportare la funzionalità di filtro Photo
con
l'ordinamento:
Index(Photo, owner_id, -date_added) Index(Photo, owner_id, -rating) Index(Photo, owner_id, -comments) Index(Photo, owner_id, -downloads) Index(Photo, size, -date_added) Index(Photo, size, -rating) Index(Photo, size, -comments) Index(Photo, size, -downloads) ... Index(Photo, tag, -date_added) Index(Photo, tag, -rating) Index(Photo, tag, -comments) Index(Photo, tag, -downloads)
Il numero di indici composti definiti è:
(number of filters + 1) * (number of orders) = 7 * 4 = 28
L'unione degli indici offre anche i seguenti vantaggi:
- Consente a un'entità
Photo
di supportare fino a 1000 tag senza limiti al numero di filtritag
per query. - Riduce il numero totale di indici, con conseguente riduzione dei costi di archiviazione e della latenza di scrittura.
Selezionare gli indici per l'app
Puoi selezionare gli indici ottimali per il database in modalità Datastore utilizzando due approcci:
Utilizzare l'unione degli indici per supportare query aggiuntive
- Richiede meno indici composti
- Riduce il costo di archiviazione per entità
- Migliora la latenza di scrittura
- Evita l'esplosione degli indici
- Le prestazioni dipendono dalla forma dei dati
Definisci un indice composto che corrisponde a più filtri in una query
- Migliora le prestazioni delle query
- Prestazioni delle query coerenti, indipendentemente dalla forma dei dati
- Deve rimanere entro il limite degli indici composti
- Aumento del costo di archiviazione per entità
- Aumento della latenza di scrittura
Quando individui gli indici ottimali per la tua app, la risposta può cambiare man mano che la forma dei dati cambia. Il campionamento delle prestazioni delle query consente di avere una buona idea delle query comuni della tua app e delle relative query lente. Con queste informazioni, puoi aggiungere indici per migliorare le prestazioni delle query comuni e lente.