Indexe

Bei jeder Abfrage in Firestore im Datastore-Modus werden die Ergebnisse anhand eines oder mehrerer Indexe berechnet, die Entitätsschlüssel in einer von den Indexattributen vorgegebenen Reihenfolge und optional auch die Ancestors der Entität enthalten. Diese Indexe werden aktualisiert, um die von den Anwendungen durchgeführten Änderungen an den Entitäten widerzuspiegeln und so ohne weitere Berechnung exakte Ergebnisse für alle Abfragen zur Verfügung zu stellen.

Es gibt zwei Arten von Indexen:

Integrierte Indexe
Bei Datenbanken im Datastore-Modus wird standardmäßig für jedes Attribut eines jeden Entitätstyps ein Index automatisch vordefiniert. Diese Indexe mit einzelnen Attributen sind für einfache Abfragetypen geeignet.
Zusammengesetzte Indexe
Zusammengesetzte Indexe indexieren mehrere Attributwerte pro Entität. Zusammengesetzte Indexe unterstützen komplexe Abfragen und sind in einer Indexkonfigurationsdatei (index.yaml) definiert.

Dieser Indextyp wird weiter unten genauer beschrieben.

Indexdefinition und -struktur

Ein Index wird auf eine Liste von Attributen einer bestimmten Entitätsart angewendet. Für jedes Attribut gilt dabei eine bestimmte Reihenfolge (aufsteigend oder absteigend). Optional kann der Index für Ancestor-Abfragen auch die Ancestors einer Entität umfassen.

Eine Indextabelle enthält eine Spalte für jedes Attribut, das in der Definition des Indexes genannt wird. Jede Tabellenzeile stellt eine Entität dar, die ein potenzielles Ergebnis für Abfragen auf Grundlage des Indexes ist. Eine Entität wird nur dann in den Index eingeschlossen, wenn jedes der verwendeten Attribute einen indexierten Wert hat. Wenn sich die Indexdefinition auf ein Attribut ohne Entitätswert bezieht, wird die Entität auch nicht im Index angezeigt und daher nie als Ergebnis einer auf dem Index basierenden Abfrage zurückgegeben.

Die Zeilen einer Indextabelle werden in der per Indexdefinition vorgegebenen Reihenfolge zuerst nach Ancestor und dann nach Attributwert sortiert. Der perfekte Index für eine Abfrage, der die effizienteste Verarbeitung ermöglicht, ist nach folgenden Attributen in der angegeben Reihenfolge definiert:

  1. In Gleichheitsfiltern verwendete Attribute
  2. In einem Ungleichheitsfilter verwendetes Attribut (nur ein einziges Attribut ist möglich)
  3. In Sortierreihenfolgen verwendete Attribute
  4. In Projections verwendete Attribute, die nicht bereits in Sortierfolgen enthalten sind

Dadurch wird sichergestellt, dass alle Ergebnisse für jede mögliche Ausführung der Abfrage in aufeinanderfolgenden Tabellenzeilen angezeigt werden. Bei Datenbanken im Datastore-Modus werden Abfragen mit einem perfekten Index in folgenden Schritten ausgeführt:

  1. Identifizierung des entsprechenden Indexes für den Typ sowie die Filterattribute, Filteroperatoren und Sortierreihenfolgen der Anfrage
  2. Scan des Indexes vom Anfang bis zur ersten Entität, die allen Filterbedingungen der Abfrage entspricht
  3. Fortsetzen des Index-Scans und Rückgabe jeder Entität, 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 Index für diese Abfrage ist eine Schlüsseltabelle 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 den gleichen Index wie oben:

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

Die beiden nachfolgenden Abfragen verwenden trotz ihrer unterschiedlichen Form ebenfalls denselben Index:

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

Der oben erstellte Index gibt Ergebnisse zurück, die beiden Abfragen entsprechen.

Indexkonfiguration

Firestore im Datastore-Modus bietet integrierte oder automatische Indexe für Abfragen der folgenden Formate:

  • Typlose Abfragen, die nur Ancestors und Schlüsselfilter benötigen
  • Abfragen, die nur Ancestors und Gleichheitsfilter benötigen
  • Abfragen, die nur Ungleichheitsfilter verwenden und auf ein einzelnes Attribut beschränkt sind
  • Abfragen, die nur Ancestor-Filter, Gleichheitsfilter für Attribute und Ungleichheitsfilter für Schlüssel verwenden
  • Abfragen ohne Filter und mit nur einer Sortierung nach einem Attribut, entweder auf- oder absteigend

Zum Beispiel werden bei Datenbanken im Datastore-Modus automatisch für jedes Attribut jeder Entitätsart zwei einzelne Attributindexe definiert, jeweils einer in aufsteigender und einer in absteigender Reihenfolge. Wenn Ihre Datenbank für ein bestimmtes Attribut keinen Index verwalten soll, können Sie dieses Attribut aus den Indexen ausschließen. Hinweis: Wenn Sie ein Attribut ausschließen, entfernen Sie es auch aus allen zusammengesetzten Indexen.

Integrierte Indexe reichen aus, um eine Vielzahl von einfachen Abfragen durchzuführen, wie etwa Gleichheitsabfragen oder einfache Ungleichheitsabfragen.

Integrierte Indexe werden nicht auf der Seite „Indexe“ der Google Cloud Console angezeigt.

Für komplexere Abfragen muss eine Anwendung zusammengesetzte bzw. mehrere manuelle Indexe definieren. Zusammengesetzte Indexe werden für die folgenden Abfragetypen benötigt:

  • Abfragen mit Ancestor- und Ungleichheitsfilter
  • Abfragen mit einem oder mehreren Ungleichheitsfiltern für ein Attribut sowie einem oder mehreren Gleichheitsfiltern für andere Attribute
  • Abfragen mit einer Sortierreihenfolge nach Schlüsseln in absteigender Reihenfolge
  • Abfragen mit mehreren Sortierreihenfolgen
  • Abfragen mit einem oder mehreren Filtern sowie einer oder mehreren Sortierreihenfolgen

Zusammengesetzte Indexe werden in der Indexkonfigurationsdatei (index.yaml) der Anwendung definiert. (Integrierte Indexe sind nicht in der Indexkonfigurationsdatei enthalten.)

Zusammengesetzte Indexe bestehen aus mehreren Attributen. Einzelne Attribute dürfen nicht aus Ihren Indexen ausgeschlossen werden.

Zusammengesetzte Indexe sind auf der Seite „Indexe“ der Google Cloud Console sichtbar. Sie können mit der Google Cloud Console keine zusammengesetzten Indexe erstellen oder aktualisieren.

Wenn die Anwendung versucht, eine Abfrage durchzuführen, die nicht mit den verfügbaren Indexen realisiert werden kann (entweder integriert oder in der Indexkonfigurationsdatei definiert), scheitert die Abfrage.

Die Datastore mode API schlägt automatisch Indexe vor, die für die meisten Anwendungen geeignet sind. Abhängig von der Nutzung des Datastore-Modus durch die Anwendung sowie der Größe und der Form der Daten sind eventuell manuelle Anpassungen der Indexe erforderlich. Beispiel: Wenn Sie Entitäten mit mehreren Attributwerten schreiben, kann dies zu einem explodierenden Index mit hohen Speicherkosten und einer höheren Schreiblatenz führen.

Der Datastore-Emulator sorgt für eine vereinfachte Verwaltung der Indexkonfigurationsdatei. Damit Abfragen nicht fehlschlagen, die nicht den benötigten Index haben, kann der Datastore-Emulator eine Indexkonfiguration erstellen, die erfolgreiche Abfragen ermöglicht. Wenn Ihr lokaler Anwendungstest jede mögliche der von Ihrer Anwendung durchführbaren Abfragen sowie jede mögliche Filterkombination und Sortierreihenfolge prüft, stellen die generierten Einträge einen kompletten Indexsatz dar. Wenn Ihr Testprozess nicht jede mögliche Abfrageform ausführt, können Sie die Indexkonfigurationsdatei prüfen und ändern, bevor Sie Ihre Indexe aktualisieren.

Weitere Informationen zu index.yaml finden Sie unter Indexkonfiguration.

Indexe bereitstellen oder löschen

Wenn Sie mit der Bearbeitung der Indexkonfigurationsdatei fertig sind, führen Sie den Befehl gcloud datastore indexes create aus, um die Indexe bereitzustellen. Weitere Informationen finden Sie unter Indexe aktualisieren.

Wenn Sie Ihre bereitgestellten Indexe nicht mehr benötigen, können Sie ungenutzte Indexe löschen.

Speicherkosten und Schreiblatenz

Indexe tragen zu Ihren Speicherkosten bei. Unter Größe des Indexeintrags wird beschrieben, wie integrierte und zusammengesetzte Indexe zur Speichergröße Ihrer Datenbank beitragen. Unter Statistiken für Firestore im Datastore-Modus finden Sie weitere Informationen zu Indexeinträgen und der Indexspeichergröße.

Indexe tragen auch zur Schreiblatenz bei. Beim Aktualisieren eines Attributwerts aktualisiert die Datenbank auch jeden zugehörigen Index. Je mehr Indexe die Datenbank aktualisieren muss, desto länger dauert der Vorgang.

Sie können die Speicherkosten senken und die Schreibleistung verbessern, indem Sie nicht verwendete Indexe löschen und Attribute von der Indexierung ausschließen. Dies verhindert auch, dass Vorgänge aufgrund von Indexlimits fehlschlagen.

Indexe und Attribute

Nachfolgend werden einige bei Indexen besonders zu beachtenden Aspekte und deren Auswirkungen auf die Attribute von Entitäten beschrieben:

Attribute mit gemischten Werttypen

Wenn zwei Entitäten Attribute mit demselben Namen, aber unterschiedlichen Werttypen haben, sortiert ein Index die Attribute zunächst nach Werttyp und anschließend nach einer für den Werttyp angemessenen Sekundärreihenfolge. Wird beispielsweise nach dem Attribut age sortiert und zwei verschiedene Entitäten haben jeweils ein Attribut mit diesem Namen (age) – eines mit ganzzahligem Wert und eines mit Stringwert – wird die Entität mit dem ganzzahligen Wert immer vor der Entität mit dem Stringwert gelistet, unabhängig von den jeweiligen Attributwerten.

Das ist besonders bei ganzzahligen und Gleitkommazahlenwerten zu beachten, da diese im Datastore-Modus wie separate Werttypen behandelt werden. Weil Ganzzahlen immer vor den Gleitkommazahlen gelistet werden, wird ein Attribut mit dem ganzzahligen Wert 38 vor dem Gleitkommazahlenwert 37.5 gereiht.

Ausgeschlossene Attribute

Wenn Sie für ein bestimmtes Attribut keinen Filter oder keine Sortierreihenfolge benötigen, können Sie dieses Attribut bei Datenbanken im Datastore-Modus aus den Indexen ausschließen, sodass keine Indexeinträge gespeichert werden. Durch Reduzierung des Speicherbedarfs für Indexeinträge verringern sich außerdem die Kosten für die Ausführung Ihrer Anwendung. Dies kann auch die Schreiblatenz verbessern. Eine Entität mit einem ausgeschlossenen Attribut verhält sich so, als wäre das Attribut nicht festgelegt. Bei Abfragen mit einem Filter oder einer Sortierreihenfolge für das ausgeschlossene Attribut wird diese Entität niemals zurückgegeben.

Das Attribut description im folgenden Beispiel wird aus den Indexen ausgeschlossen:

C#

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore C# API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

Entity task = new Entity()
{
    Key = _db.CreateKeyFactory("Task").CreateKey("sampleTask"),
    ["category"] = "Personal",
    ["created"] = new DateTime(1999, 01, 01, 0, 0, 0, DateTimeKind.Utc),
    ["done"] = false,
    ["priority"] = 4,
    ["percent_complete"] = 10.0,
    ["description"] = new Value()
    {
        StringValue = "Learn Cloud Datastore",
        ExcludeFromIndexes = true
    },
};

Go

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Go API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

type Task struct {
	Category        string
	Done            bool
	Priority        int
	Description     string `datastore:",noindex"`
	PercentComplete float64
	Created         time.Time
}
task := &Task{
	Category:        "Personal",
	Done:            false,
	Priority:        4,
	Description:     "Learn Cloud Datastore",
	PercentComplete: 10.0,
	Created:         time.Now(),
}

Java

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Java API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

Entity task =
    Entity.newBuilder(taskKey)
        .set("category", "Personal")
        .set("created", Timestamp.now())
        .set("done", false)
        .set("priority", 4)
        .set("percent_complete", 10.0)
        .set(
            "description",
            StringValue.newBuilder("Learn Cloud Datastore").setExcludeFromIndexes(true).build())
        .build();

Node.js

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Node.js API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

const task = [
  {
    name: 'category',
    value: 'Personal',
  },
  {
    name: 'created',
    value: new Date(),
  },
  {
    name: 'done',
    value: false,
  },
  {
    name: 'priority',
    value: 4,
  },
  {
    name: 'percent_complete',
    value: 10.0,
  },
  {
    name: 'description',
    value: 'Learn Cloud Datastore',
    excludeFromIndexes: true,
  },
];

PHP

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore PHP API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

$task = $datastore->entity(
    $key,
    [
        'category' => 'Personal',
        'created' => new DateTime(),
        'done' => false,
        'priority' => 4,
        'percent_complete' => 10.0,
        'description' => 'Learn Cloud Datastore'
    ],
    ['excludeFromIndexes' => ['description']]
);

Python

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Python API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

from google.cloud import datastore

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

key = client.key("Task")
task = datastore.Entity(key, exclude_from_indexes=("description",))
task.update(
    {
        "category": "Personal",
        "description": "Learn Cloud Datastore",
        "created": datetime.datetime.now(tz=datetime.timezone.utc),
        "done": False,
        "priority": 4,
        "percent_complete": 10.5,
    }
)
client.put(task)

Ruby

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Ruby API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

task = datastore.entity "Task" do |t|
  t["category"] = "Personal"
  t["created"] = Time.now
  t["done"] = false
  t["priority"] = 4
  t["percent_complete"] = 10.0
  t["description"] = "Learn Cloud Datastore"
  t.exclude_from_indexes! "description", true
end

GQL

Nicht zutreffend

Die Abfrage im folgenden Beispiel gibt keine Ergebnisse zurück, wenn das Attribut description ausgeschlossen wurde:

C#

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore C# API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

Query query = new Query("Task")
{
    Filter = Filter.Equal("description", "Learn Cloud Datastore")
};

Go

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Go API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

query := datastore.NewQuery("Tasks").
	FilterField("Description", "=", "A task description")

Java

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Java API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

Query<Entity> query =
    Query.newEntityQueryBuilder()
        .setKind("Task")
        .setFilter(PropertyFilter.eq("description", "A task description"))
        .build();

Node.js

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Node.js API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

const query = datastore
  .createQuery('Task')
  .filter(new PropertyFilter('description', '=', 'A task description.'));

PHP

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore PHP API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

$query = $datastore->query()
    ->kind('Task')
    ->filter('description', '=', 'A task description.');

Python

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Python API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

from google.cloud import datastore

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

query = client.query(kind="Task")
query.add_filter(filter=PropertyFilter("description", "=", "Learn Cloud Datastore"))

Ruby

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Ruby API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

query = datastore.query("Task")
                 .where("description", "=", "A task description.")

GQL


# Will not return any results!
SELECT * FROM Task WHERE description = 'A task description.'

Sie können das Attribut später wieder zu "indexiert" ändern.

Hinweis: Wenn Sie ein Attribut von "ausgeschlossen" zu "indexiert" ändern, sind die vor der Änderung erstellten Entitäten nicht von der Änderung betroffen. Abfragen, die nach solchen Attributen filtern, geben die bereits bestehenden Entitäten nicht als Ergebnis aus, da diese bei Erstellung der Entität nicht in den Abfrageindex geschrieben wurden. Damit die Entitäten für zukünftige Abfragen zur Verfügung stehen, müssen Sie sie neu in die Datenbank schreiben, damit sie in die entsprechenden Indexe aufgenommen werden. Für jede solche bereits bestehende Entität sind also folgende Schritte nötig:

  1. Suchen Sie die Entität (Get).
  2. Schreiben Sie die Entität zurück in die Datenbank (Put).

Wenn Sie ein Attribut von "indexiert" zu "ausgeschlossen" ändern, wirkt sich auch dies nur auf Entitäten aus, die nach der Änderung in die Datenbank geschrieben wurden. Die Indexeinträge für etwaige bestehende Entitäten mit diesem Attribut bleiben weiterhin bestehen, bis die Entitäten aktualisiert oder gelöscht werden. Um ungewünschte Ergebnisse zu vermeiden, müssen Sie alle Abfragen, die nach diesem (nun ausgeschlossenen) Attribut filtern oder sortieren, aus Ihrem Code entfernen.

Indexbeschränkungen

Firestore im Datastore-Modus schränkt die Anzahl und die Gesamtgröße von Indexeinträgen ein, die mit einer einzelnen Entität verknüpft werden können. Diese Beschränkungen sind sehr großzügig bemessen und sind für die meisten Anwendungen nicht relevant. Unter bestimmten Umständen könnten Sie jedoch dennoch auf diese Beschränkungen treffen.

Wie oben beschrieben, erstellt eine Datenbank im Datastore-Modus für jedes Attribut jeder Entität einen Eintrag in einem vordefinierten Index. Hiervon ausgenommen sind Attribute, die Sie ausdrücklich aus Ihren Indexen ausgeschlossen haben. Das Attribut kann auch in zusätzlichen benutzerdefinierten Indexen enthalten sein, die Sie in der Indexkonfigurationsdatei (index.yaml) angegeben haben. Sofern eine Entität keine Listenattribute aufweist, hat sie in jedem dieser benutzerdefinierten Indexe höchstens einen Eintrag (für Nicht-Ancestor-Indexe) bzw. einen Eintrag für jeden Ancestor der Entität (für Ancestor-Indexe). Jeder dieser Einträge muss aktualisiert werden, wenn sich der Wert des Attributs ändert.

Bei einem Attribut, das für jede Entität über einen einzelnen Wert verfügt, muss jeder mögliche Wert nur einmal pro Entität im vordefinierten Index des Attributs gespeichert werden. Trotzdem ist es möglich, dass eine Entität mit einer großen Anzahl solcher Einzelwert-Attribute das Indexeintrags- oder Eintragsgrößenlimit überschreitet. Eine Entität, die mehrere Werte für dasselbe Attribut haben kann, erfordert einen eigenen Indexeintrag für jeden Wert. Wenn die Anzahl der möglichen Werte besonders groß ist, kann es auch hier passieren, dass eine solche Entität das Eintragslimit überschreitet.

Bei Entitäten mit mehreren Attributen, die jeweils mehrere Werte annehmen können, wird die Situation noch schlimmer. Der Index muss einen Eintrag für jede mögliche Kombination von Attributwerten enthalten, um einer solchen Entität gerecht zu werden. Benutzerdefinierte Indexe, die sich auf mehrere Attribute beziehen, die jeweils mehrere mögliche Werte haben, können durch diese Kombinationen "explodieren". Das heißt, sie können extrem groß werden, da sie selbst für eine Entität mit einer relativ geringen Anzahl an möglichen Attributwerten eine große Anzahl an Einträgen benötigen. Diese explodierenden Indexe können den Speicherbedarf einer Entität erheblich erhöhen, da sehr viele Indexeinträge gespeichert werden müssen. Explodierende Indexe können außerdem dazu führen, dass die Entität ihre erlaubte Indexeintragsanzahl oder -größe übersteigt.

Betrachten wir den folgenden Code:

C#

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore C# API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

Entity task = new Entity()
{
    Key = _db.CreateKeyFactory("Task").CreateKey("sampleTask"),
    ["tags"] = new ArrayValue() { Values = { "fun", "programming", "learn" } },
    ["collaborators"] = new ArrayValue() { Values = { "alice", "bob", "charlie" } },
    ["created"] = DateTime.UtcNow
};

Go

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Go API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

task := &Task{
	Tags:          []string{"fun", "programming", "learn"},
	Collaborators: []string{"alice", "bob", "charlie"},
	Created:       time.Now(),
}

Java

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Java API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

Entity task =
    Entity.newBuilder(taskKey)
        .set("tags", "fun", "programming", "learn")
        .set("collaborators", "alice", "bob", "charlie")
        .set("created", Timestamp.now())
        .build();

Node.js

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Node.js API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

const task = {
  method: 'insert',
  key: datastore.key('Task'),
  data: {
    tags: ['fun', 'programming', 'learn'],
    collaborators: ['alice', 'bob', 'charlie'],
    created: new Date(),
  },
};

PHP

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore PHP API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

$task = $datastore->entity(
    $datastore->key('Task'),
    [
        'tags' => ['fun', 'programming', 'learn'],
        'collaborators' => ['alice', 'bob', 'charlie'],
        'created' => new DateTime(),
    ]
);

Python

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Python API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

from google.cloud import datastore

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

task = datastore.Entity(client.key("Task"))
task.update(
    {
        "tags": ["fun", "programming", "learn"],
        "collaborators": ["alice", "bob", "charlie"],
        "created": datetime.datetime.now(tz=datetime.timezone.utc),
    }
)

Ruby

Informationen zum Installieren und Verwenden der Clientbibliothek für Cloud Datastore finden Sie unter Cloud Datastore-Clientbibliotheken. Weitere Informationen finden Sie in der Referenzdokumentation zur Cloud Datastore Ruby API.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich bei Cloud Datastore zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

task = datastore.entity "Task" do |t|
  t["tags"] = ["fun", "programming", "learn"]
  t["collaborators"] = ["alice", "bob", "charlie"]
  t["created"] = Time.now
end

GQL

Nicht zutreffend

Es wird eine Task-Entität mit drei Werten für das Attribut tags, drei Werten für das Attribut collaborators und dem aktuellen Datum als Wert für das Attribut created erstellt. In diesem Fall werden 9 Indexeinträge benötigt – einer für jede mögliche Kombination aus Attributwerten:

('fun', 'alice', NOW())
('fun', 'bob', NOW())
('fun', 'charlie', NOW())

('programming', 'alice', NOW())
('programming', 'bob', NOW())
('programming', 'charlie', NOW())

('learn', 'alice', NOW())
('learn', 'bob', NOW())
('learn', 'charlie', NOW())

Wenn dasselbe Attribut mehrere Male wiederholt wird, kann Firestore im Datastore-Modus explodierende Indexe erkennen und alternative Indexe vorschlagen. In allen anderen Fällen (wie etwa bei der in diesem Beispiel definierten Abfrage) erstellt eine Datenbank im Datastore-Modus einen explodierenden Index. In diesem Fall können Sie den explodierenden Index umgehen, indem Sie einen Index mithilfe Ihrer Indexkonfigurationsdatei manuell definieren:

indexes:
- kind: Task
  properties:
  - name: tags
  - name: created
- kind: Task
  properties:
  - name: collaborators
  - name: created

Dadurch wird die Anzahl der erforderlichen Einträge auf nur (|tags| * |created| + |collaborators| * |created|) bzw. 6 statt 9 Einträgen reduziert:

('fun', NOW())
('programming', NOW())
('learn', NOW())

('alice', NOW())
('bob', NOW())
('charlie', NOW())

Jeder commit-Vorgang, der dazu führt, dass ein Index das Eintrags- oder Größenlimit für Indexe überschreitet, schlägt fehl. Der Text der Fehlermeldung beschreibt, welches Limit überschritten wurde ("Too many indexed properties" oder "Index entries too large") und welcher benutzerdefinierte Index die Ursache war. Wenn Sie einen neuen Index erstellen, der beim Erstellen die Limits für eine Entität überschreiten würde, schlagen Abfragen des Index fehl und der Index wird in der Google Cloud Console mit dem Status Error angezeigt. So verarbeiten Sie solche Error-Indexe:

  1. Entfernen Sie den Index aus der Indexkonfigurationsdatei (index.yaml).
  2. Entfernen Sie den Index mithilfe der Google Cloud CLI aus der Datenbank. Verwenden Sie dazu den Befehl datastore indexes cleanup, wie unter Nicht verwendete Indexe löschen beschrieben.
  3. Entweder
    • Formulieren Sie die Indexdefinition und die entsprechenden Abfragen um oder
    • entfernen Sie die Entitäten, die dazu führen, dass ein Index explodiert.
  4. Fügen Sie den Index wieder zu index.yaml hinzu.
  5. Fügen Sie der Datenbank über die Google Cloud CLI den Index hinzu. Führen Sie dazu den Befehl datastore indexes create aus, wie unter Indexe aktualisieren beschrieben.

Das Explodieren von Indexen können Sie verhindern, indem Sie Abfragen vermeiden, für die ein benutzerdefinierter Index erforderlich ist, der ein Listenattribut verwendet. Dazu gehören wie oben beschrieben Abfragen mit mehreren Sortierreihenfolgen oder einer Kombination aus Gleichheits- und Ungleichheitsfiltern.

Indexe für Projektionen

Für Projektionsabfragen müssen alle in der Projektion definierten Attribute in einem Index enthalten sein. Der Datastore-Emulator generiert automatisch die benötigten Indexe für die Indexkonfigurationsdatei index.yaml, die mit der Anwendung hochgeladen wird.

Die Anzahl der benötigten Indexe können Sie beispielsweise durch konstantes Projizieren derselben Attribute reduzieren, auch wenn nicht immer alle benötigt werden. Diese Abfragen benötigen beispielsweise zwei getrennte Indexe:

SELECT priority, percent_complete FROM Task

SELECT priority, percent_complete, created FROM Task

Wenn Sie jedoch immer die Attribute priority, percent_complete und created projizieren, auch wenn created nicht benötigt wird, ist nur ein Index erforderlich.

Wenn Sie eine bestehende Abfrage in eine Projektionsabfrage umwandeln, müssen Sie gegebenenfalls einen neuen Index erstellen, wenn die Attribute für die Projektion nicht bereits in einem anderen Teil der Abfrage enthalten sind. Angenommen, Sie haben eine bestehende Abfrage:

SELECT * FROM Task
WHERE priority > 1
ORDER BY priority, percent_complete

Sie benötigt diesen Index:

indexes:
- kind: Task
  properties:
  - name: priority
  - name: percent_complete

Wenn diese in eine dieser Projektionsabfragen konvertiert wird:

SELECT created FROM Task
WHERE priority > 1
ORDER BY priority, percent_complete

SELECT priority, percent_complete, created FROM Task
WHERE priority > 1
ORDER BY priority, percent_complete

Ein neues Attribut (created) wird eingeführt. Dies erfordert die Erstellung eines neuen Indexes:

indexes:
- kind: Task
  properties:
  - name: priority
  - name: percent_complete
  - name: created

Für die folgende Abfrage müsste der Index dagegen nicht geändert werden:

SELECT priority, percent_complete FROM Task
WHERE priority > 1
ORDER BY priority, percent_complete

ändert den erforderlichen Index nicht, da die projizierten Attribute priority und percent_complete bereits in der vorhandenen Abfrage enthalten sind.

Mehrere Datenbanken

Sie können gcloud firestore verwenden, um einen einzelnen Index für den Datastore-Modus zu verwalten, oder gcloud datastore mit einer index.yaml-Datei, um alle Indexe in einer Datenbank zu verwalten.

gcloud Firestore
gcloud firestore indexes composite create --api-scope=datastore-mode-api  --query-scope=QUERY_SCOPE --database=DATABASE_ID
gcloud datastore
gcloud alpha datastore indexes create index.yaml --database=DATABASE_ID

Ersetzen Sie Folgendes:

  • DATABASE_ID: eine Datenbank-ID.
  • QUERY_SCOPE: entweder collection-recursive für Ancestor-Indexe oder collection-group für Nicht-Ancestor-Indexe.