Indexe optimieren

Auf dieser Seite werden Konzepte beschrieben, die bei der Auswahl von Firestore-Indexen im Datastore-Modus für Ihre Anwendung zu berücksichtigen sind.

Firestore im Datastore-Modus verwendet für alle Abfragen Indexe und bietet dadurch eine hohe Abfrageleistung. Die Leistung für die meisten Abfragen hängt von der Größe der Ergebnismenge und nicht von der Gesamtgröße der Datenbank ab.

Firestore im Datastore-Modus definiert integrierte Indexe für jedes Attribut in einer Entität. Diese Indexe mit einzelnen Attributen unterstützen eine große Anzahl einfacher Abfragen. Firestore im Datastore-Modus arbeitet mit einem Feature zur Indexzusammenführung, mit dem integrierte Indexe in Ihrer Datenbank zusammengeführt werden können. Hierdurch werden zusätzliche Abfragen möglich. Bei komplexeren Abfragen müssen Sie zusammengesetzte Indexe im Voraus definieren.

Auf dieser Seite wird das Feature zur Indexzusammenführung beschrieben, da es zwei wichtige Möglichkeiten zur Indexoptimierung bietet:

  • Beschleunigen von Abfragen
  • Reduzieren der Anzahl zusammengesetzter Indexe

Das folgende Beispiel zeigt das praktische Funktionieren der Indexzusammenführungsfunktion.

Photo-Entitäten filtern

Betrachten Sie eine Datenbank im Datastore-Modus mit Entitäten der Art Photo:

Foto
Attribut Werttyp Beschreibung
owner_id String Nutzer-ID
tag Stringarray Tokenisierte Keywords
size Integer Aufzählung:
  • 1 icon
  • 2 medium
  • 3 large
coloration Ganzzahl Aufzählung:
  • 1 black & white
  • 2 color

Angenommen, Sie benötigen ein Anwendungsfeature, mit dem Nutzer Photo-Entitäten anhand eines logischen AND der folgenden Elemente abfragen können:

  • Verfügbar sind bis zu drei Filter entsprechend den Attributen:

    • owner_id
    • size
    • coloration
  • Sie verwenden einen tag-Suchstring. Die Anwendung tokenisiert den Suchstring in Tags und fügt für jedes Tag einen Filter hinzu.

    Die Anwendung wandelt beispielsweise den Suchstring outside, family in die Abfragefilter tag=outside und tag=family um.

Mithilfe der integrierten Indexe und des Indexzusammenführungs-Features von Firestore im Datastore-Modus können Sie die Indexanforderungen dieser Photo-Filterfunktion erfüllen, ohne zusätzliche zusammengesetzte Indexe hinzufügen zu müssen.

Die integrierten Indexe für Photo-Entitäten unterstützen Abfragen mit einzelnem Filter wie z. B.:

Python

from google.cloud import datastore

# For help authenticating your client, visit
# https://cloud.google.com/docs/authentication/getting-started
client = datastore.Client()

query_owner_id = client.query(kind="Photo", filters=[("owner_id", "=", "user1234")])

query_size = client.query(kind="Photo", filters=[("size", "=", 2)])

query_coloration = client.query(kind="Photo", filters=[("coloration", "=", 2)])

Die Photo-Filterfunktion erfordert auch Abfragen, die mehrere Gleichheitsfilter mit einem logischen AND kombinieren:

Python

from google.cloud import datastore

# For help authenticating your client, visit
# https://cloud.google.com/docs/authentication/getting-started
client = datastore.Client()

query_all_properties = client.query(
    kind="Photo",
    filters=[
        ("owner_id", "=", "user1234"),
        ("size", "=", 2),
        ("coloration", "=", 2),
        ("tag", "=", "family"),
    ],
)

Der Firestore in Datastore-Modus kann diese Abfragen unterstützen, indem er integrierte Indizes zusammenführt.

Indexzusammenführung

Firestore im Datastore-Modus kann die Indexzusammenführung verwenden, wenn Ihre Abfrage und Ihre Indexe alle die folgenden Einschränkungen erfüllen:

  • Die Abfrage verwendet nur Gleichheitsfilter (=)
  • Es gibt keinen zusammengesetzten Index, der perfekt mit den Filtern und der Sortierung der Abfrage übereinstimmt
  • Jeder Gleichheitsfilter führt mindestens einen vorhandenen Index mit derselben Sortierung wie die Abfrage zusammen

In diesem Fall kann Firestore im Datastore-Modus mit vorhandenen Indexen die Abfrage unterstützen, anstatt einen zusätzlichen zusammengesetzten Index konfigurieren zu müssen.

Wenn zwei oder mehr Indexe nach denselben Kriterien sortiert sind, kann Firestore im Datastore-Modus die Ergebnisse mehrerer Indexscans zusammenführen, um die Ergebnisse zu finden, die allen solchen Indexen gemeinsam sind. Firestore im Datastore-Modus kann integrierte Indexe zusammenführen, da alle Werte nach Entitätsschlüssel sortiert werden.

Durch das Zusammenführen integrierter Indexe unterstützt Firestore im Datastore-Modus Abfragen mit Gleichheitsfiltern für mehrere Attribute:

Python

from google.cloud import datastore

# For help authenticating your client, visit
# https://cloud.google.com/docs/authentication/getting-started
client = datastore.Client()

query_all_properties = client.query(
    kind="Photo",
    filters=[
        ("owner_id", "=", "user1234"),
        ("size", "=", 2),
        ("coloration", "=", 2),
        ("tag", "=", "family"),
    ],
)

Firestore im Datastore-Modus kann auch Indexergebnisse aus mehreren Bereichen desselben Indexes zusammenführen. Durch Zusammenführen verschiedener Bereiche des integrierten Index für das tag-Attribut unterstützt Firestore im Datastore-Modus Abfragen, bei denen mehrere tag-Filter in einem logischen AND kombiniert werden:

Python

from google.cloud import datastore

# For help authenticating your client, visit
# https://cloud.google.com/docs/authentication/getting-started
client = datastore.Client()

query_tag = client.query(
    kind="Photo",
    filters=[
        ("tag", "=", "family"),
        ("tag", "=", "outside"),
        ("tag", "=", "camping"),
    ],
)

query_owner_size_color_tags = client.query(
    kind="Photo",
    filters=[
        ("owner_id", "=", "user1234"),
        ("size", "=", 2),
        ("coloration", "=", 2),
        ("tag", "=", "family"),
        ("tag", "=", "outside"),
        ("tag", "=", "camping"),
    ],
)

Die Abfragen, die von zusammengeführten integrierten Indexen unterstützt werden, vervollständigen die für die Filterfunktion Photo erforderlichen Abfragen. Beachten Sie, dass für die Unterstützung der Filterfunktion Photo keine zusätzlichen zusammengesetzten Indexe erforderlich sind.

Bei der Auswahl der optimalen Indexe für Ihre Anwendung ist es wichtig, das Indexzusammenführungs-Feature zu verstehen. Durch das Zusammenführen von Indexen ist Firestore im Datastore-Modus flexibler bei Abfragen, die Leistung kann aber möglicherweise beeinträchtigt sein. Im nächsten Abschnitt wird die Leistung bei der Indexzusammenführung und die Leistungsverbesserung durch Hinzufügen zusammengesetzter Indexe beschrieben.

Den perfekten Index finden

Der Index wird in der in der Indexdefinition angegebenen Reihenfolge zuerst nach dem Ancestor und dann nach Attributwerten sortiert. Der perfekte zusammengesetzte Index für eine Abfrage, der die effizienteste Ausführung der Abfrage ermöglicht, ist nach den folgenden Attributen in der angegebenen Reihenfolge definiert:

  1. In Gleichheitsfiltern verwendete Attribute
  2. In Sortierreihenfolgen verwendete Attribute
  3. Im Filter „distinctOn“ verwendete Eigenschaften
  4. Attribute, die in Bereichs- und Ungleichheitsfiltern verwendet werden und nicht bereits in Sortierfolgen enthalten sind
  5. In Aggregationen und Projektionen verwendete Attribute, die nicht bereits in Sortierfolgen sowie Bereichs- und Ungleichheitsfiltern enthalten sind

Dadurch wird sichergestellt, dass alle Ergebnisse für jede mögliche Ausführung der Abfrage berücksichtigt werden. Firestore-Datenbanken im Datastore-Modus führen mithilfe der folgenden Schritte eine Abfrage mit einem perfekten Index aus:

  1. Identifizierung des entsprechenden Indexes für den Typ sowie die Filterattribute, Filteroperatoren und Sortierreihenfolgen der Anfrage
  2. Scannt vom Anfang des Index bis zur ersten Entität, die alle oder einen Teil der Filterbedingungen der Abfrage erfüllt
  3. Fortsetzen des Index-Scans und Rückgabe jeder Entität, die alle Filterbedingungen erfüllt, bis
    • Cloud Datastore auf eine Entität trifft, die den Filterbedingungen nicht entspricht, oder
    • das Index-Ende erreicht ist oder
    • die maximale Anzahl von Ergebnissen, die von der Abfrage angefordert wurden, erreicht ist.

Betrachten Sie beispielsweise die folgende Abfrage:

SELECT * FROM Task
WHERE category = 'Personal'
  AND priority < 3
ORDER BY priority DESC

Der perfekte zusammengesetzte Index für diese Abfrage ist ein Index von Schlüsseln für Entitäten vom Typ Task mit Spalten für die Werte der Attribute category und priority. Der Index wird zuerst in aufsteigender Reihenfolge nach category und dann in absteigender Reihenfolge nach priority sortiert:

indexes:
- kind: Task
  properties:
  - name: category
    direction: asc
  - name: priority
    direction: desc

Zwei Abfragen der gleichen Form, aber mit verschiedenen Filterwerten verwenden denselben Index. Die folgende Abfrage verwendet beispielsweise denselben Index wie die vorherige Abfrage:

SELECT * FROM Task
WHERE category = 'Work'
  AND priority < 5
ORDER BY priority DESC

Für diesen Index

indexes:
- kind: Task
  properties:
  - name: category
    direction: asc
  - name: priority
    direction: asc
  - name: created
    direction: asc

Der ältere Index kann die beiden folgenden Abfragen erfüllen:

SELECT * FROM Task
WHERE category = 'Personal'
  AND priority = 5
ORDER BY created ASC

und

SELECT * FROM Task
WHERE category = 'Work'
ORDER BY priority ASC, created ASC

Indexauswahl optimieren

In diesem Abschnitt werden die Leistungsmerkmale der Indexzusammenführung und zwei Optimierungsmöglichkeiten im Zusammenhang mit der Indexzusammenführung beschrieben:

  • Fügen Sie zusammengesetzte Indexe hinzu, um Abfragen zu beschleunigen, die auf zusammengeführten Indexen basieren
  • Reduzieren Sie die Anzahl der zusammengesetzten Indexe, indem Sie zusammengeführte Indexe nutzen

Leistung bei Indexzusammenführung

Bei einer Indexzusammenführung erreicht Firestore im Datastore-Modus zusätzliche Effizienz mit einem Zig-Zag-Merge-Join-Algorithmus. Mithilfe dieses Algorithmus verbindet der Datastore-Modus potenzielle Übereinstimmungen aus mehreren Indexscans, um eine Ergebnismenge passend zu einer Abfrage zu erzeugen. Ein weiteres Merkmal der Indexzusammenführung ist, dass Filterkomponenten zur Lesezeit anstatt zur Schreibzeit kombiniert werden. Deshalb hängt die Leistung – im Gegensatz zu den meisten Firestore-Abfragen im Datastore-Modus, bei denen die Leistung nur von der Größe der Ergebnismenge bestimmt wird – bei Abfragen mit Indexzusammenführung von den Filtern in der Abfrage und von der Anzahl der berücksichtigten potenziellen Übereinstimmungen ab.

Die Leistung einer Indexzusammenführung ist am besten, wenn jede potenzielle Übereinstimmung in einem Index die Abfragefilter erfüllt. In diesem Fall beträgt die Leistung O(R * I), wobei R die Größe der Ergebnismenge und I die Anzahl der gescannten Indexe ist.

Die Leistung ist am geringsten, wenn die Datenbank viele potenzielle Übereinstimmungen berücksichtigen muss, aber nur wenige davon die Abfragefilter erfüllen. In diesem Fall beträgt die Leistung O(S), wobei S die Größe des kleinsten Satzes potenzieller Entitäten aus einem einzelnen Indexscan ist.

Die tatsächliche Leistung hängt von der Form der Daten ab. Die durchschnittliche Anzahl der Entitäten, die für jedes zurückgegebene Ergebnis berücksichtigt werden, beträgt O(S/(R * I)). Die Abfragequalität verschlechtert sich, wenn viele Entitäten mit jedem Indexscan übereinstimmen, aber nur wenige Entitäten mit der Abfrage als Ganzes übereinstimmen, d. h. wenn R klein und S groß ist.

So können Sie jedoch das Risiko minimieren:

  • Der Abfrageplaner sucht eine Entität erst, wenn die Entität mit der gesamten Abfrage übereinstimmt.

  • Der Zig-Zag-Algorithmus muss nicht alle Ergebnisse finden, um das jeweils nächste Ergebnis zurückzugeben. Wenn Sie die ersten zehn Ergebnisse anfordern, bezahlen Sie nur für die Latenz, die durch die Ergebnissuche verursacht wird.

  • Der Zig-Zag-Algorithmus überspringt große Teile falsch positiver Ergebnisse. Die Leistung ist nur gering, wenn falsch positive Ergebnisse zwischen den Scans in der Sortierreihenfolge komplett verflochten sind (in Sortierreihenfolge).

  • Die Latenz hängt von der Anzahl der Entitäten ab, die in den einzelnen Indexscans gefunden werden, und nicht von der Anzahl der Entitäten, die mit dem jeweiligen Filter übereinstimmen. Wie im nächsten Abschnitt gezeigt, können Sie zusammengesetzte Indexe hinzufügen, um die Leistung der Indexzusammenführung zu verbessern.

Abfrage für Indexzusammenführung beschleunigen

Wenn Firestore im Datastore-Modus Indexe zusammenführt, wird jeder Indexscan häufig einem einzelnen Filter in der Abfrage zugeordnet. Sie können die Abfrageleistung verbessern, indem Sie zusammengesetzte Indexe hinzufügen, die mit mehreren Filtern in der Abfrage übereinstimmen.

Sehen Sie sich diese Abfrage an:

Python

from google.cloud import datastore

# For help authenticating your client, visit
# https://cloud.google.com/docs/authentication/getting-started
client = datastore.Client()

query_owner_size_tag = client.query(
    kind="Photo",
    filters=[
        ("owner_id", "=", "username"),
        ("size", "=", 2),
        ("tag", "=", "family"),
    ],
)

Jeder Filter wird einem Indexscan in den folgenden integrierten Indexen zugeordnet:

Index(Photo, owner_id)
Index(Photo, size)
Index(Photo, tag)

Wenn Sie den zusammengesetzten Index Index(Photo, owner_id, size) hinzufügen, wird die Abfrage zwei statt drei Indexscans zugeordnet:

#  Satisfies both 'owner_id=username' and 'size=2'
Index(Photo, owner_id, size)
Index(Photo, tag)

Stellen Sie sich ein Szenario mit vielen großen Bildern vor, unter denen viele schwarz-weiße, aber wenige große Panoramabilder sind. Eine Abfragefilterung nach sowohl Panorama- als auch Schwarz-Weiß-Bildern wäre dann langsam, wenn die integrierten Indexe zusammengeführt werden:

Python

from google.cloud import datastore

# For help authenticating your client, visit
# https://cloud.google.com/docs/authentication/getting-started
client = datastore.Client()

query_size_coloration = client.query(
    kind="Photo", filters=[("size", "=", 2), ("coloration", "=", 1)]
)

Zur Verbesserung der Abfrageleistung können Sie den Wert von S (kleinster Satz von Entitäten in einem einzelnen Indexscan) auf O(S/(R * I)) senken. Fügen Sie hierfür den folgenden zusammengesetzten Index hinzu:

Index(Photo, size, coloration)

Im Vergleich zur Verwendung von zwei integrierten Indexen erzeugt dieser zusammengesetzte Index weniger potenzielle Ergebnisse für dieselben zwei Abfragefilter. Dieser Ansatz verbessert die Leistung erheblich, wenn auf einen zweiten Index verzichtet wird.

Anzahl der zusammengesetzten Indexe mit Indexzusammenführung reduzieren

Obwohl zusammengesetzte Indexe, die genau mit den Filtern in einer Abfrage übereinstimmen, die beste Leistung erbringen, ist es nicht immer am besten oder möglich, einen zusammengesetzten Index für jede Filterkombination hinzuzufügen. Sie müssen Ihre zusammengesetzten Indexe gegen Folgendes abwägen:

  • Zusammengesetzte Indexlimits:

    Limit Menge
    Maximale Anzahl zusammengesetzter Indexe für eine Datenbank
    Maximale Summe der Größe von zusammengesetzten Indexeinträgen einer Entität 2 MiB
    Maximale Summe der folgenden Elemente für eine Entität:
    • Anzahl von indexierten Attributwerten
    • Anzahl von zusammengesetzten Indexeinträgen
    20.000
  • Speicherkosten für jeden zusätzlichen Index
  • Auswirkungen auf die Schreiblatenz.

Indexierungsprobleme treten häufig bei Feldern mit mehreren Werten wie dem tag-Attribut der Photo-Entitäten auf.

Angenommen, die Filterfunktion Photo muss absteigende Sortierklauseln anhand von vier zusätzlichen Attributen unterstützen:

Foto
Attribut Werttyp Beschreibung
date_added Ganzzahl Datum/Uhrzeit
rating Fließkommazahl Gesamtbewertung des Nutzers
comment_count Integer Anzahl der Kommentare
download_count Ganzzahl Anzahl der Downloads

Wenn Sie das Feld tag ignorieren, ist es möglich, zusammengesetzte Indexe auszuwählen, die mit jeder Kombination von Photo-Filtern übereinstimmen:

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)

Die Gesamtzahl der zusammengesetzten Indexe ist:

2^(number of filters) * (number of different orders) = 2 ^ 3 * 4 = 32 composite indexes

Wenn Sie versuchen, bis zu drei tag-Filter zu unterstützen, beträgt die Gesamtzahl der zusammengesetzten Indexe:

2 ^ (3 + 3 tag filters) * 4 = 256 indexes.

Indexe, die Attribute mit mehreren Werten wie tag enthalten, führen außerdem zu Problemen mit explodierenden Indexen, die die Speicherkosten und die Schreiblatenz erhöhen.

Zur Unterstützung von Filtern im Feld tag für dieses Feature können Sie die Gesamtzahl der Indexe durch zusammengeführte Indexe reduzieren. Der folgende Satz zusammengesetzter Indexe ist das Minimum, das erforderlich ist, um die Filterfunktion Photo mit Sortierung zu unterstützen:

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)

Die Anzahl der definierten zusammengesetzten Indexe ist:

(number of filters + 1) * (number of orders) = 7 * 4 = 28

Die Indexzusammenführung bietet außerdem folgende Vorteile:

  • Sie ermöglicht einer Photo-Entität die Unterstützung von bis zu 1.000 Tags ohne Begrenzung der Anzahl der tag-Filter pro Abfrage.
  • Sie reduziert die Gesamtzahl der Indexe, wodurch die Speicherkosten und die Schreiblatenz sinken.

Indexe für Ihre Anwendung auswählen

Sie können optimale Indexe für Ihre Datenbank im Datastore-Modus auswählen. Dafür gibt es zwei Ansätze:

  • Verwenden Sie die Indexzusammenführung, um zusätzliche Abfragen zu unterstützen

    • Erfordert weniger zusammengesetzte Indexe
    • Reduziert die Speicherkosten pro Entität
    • Verbessert die Schreiblatenz
    • Vermeidet explodierende Indexe
    • Die Leistung hängt von der Form der Daten ab
  • Definieren Sie einen zusammengesetzten Index, der mit mehreren Filtern in einer Abfrage übereinstimmt

    • Verbessert die Abfrageleistung
    • Gleichbleibende Abfrageleistung, die nicht von der Form der Daten abhängt
    • Muss unter dem Limit von zusammengesetzten Indexen bleiben
    • Erhöhte Speicherkosten pro Entität
    • Erhöhte Schreiblatenz

Die optimalen Indexe für Ihre Anwendung hängen von der Form Ihrer Daten ab. Wenn Sie die Abfrageleistung erst einmal mit Stichproben testen, bekommen Sie eine Vorstellung davon, welche Art von Abfragen bei Ihrer Anwendung häufig vorkommt und welche Abfragen langsam sind. Entsprechend den Ergebnissen Ihrer Stichproben können Sie Indexe hinzufügen, um die Leistung derjenigen Anfragen zu verbessern, die sowohl häufig vorkommen als auch langsam sind.