Abfrage mit Bereichs- und Ungleichheitsfiltern für mehrere Attribute

Firestore im Datastore-Modus unterstützt die Verwendung von Bereichs- und Ungleichheitsfiltern für mehrere Attribute in einer einzelnen Abfrage. Sie können jetzt Bereichs- und Ungleichheitsbedingungen für mehrere Attribute festlegen und die Anwendungsentwicklung vereinfachen, indem Sie die Implementierung der Nachfilterlogik an Firestore im Datastore-Modus delegieren.

Bereichs- und Ungleichheitsfilter für mehrere Attribute

Die folgende Abfrage gibt alle Nutzer zurück, deren Alter größer als 35 und deren Größe zwischen 60 und 70 liegt. Dazu werden Bereichsfilter für Alter und Größe verwendet.

GQL

 SELECT * FROM /users WHERE age > 35 AND height > 60 AND height < 70;

Java


  Query<Entity> query =
    Query.newEntityQueryBuilder()
      .setKind("users")
      .setFilter(
        CompositeFilter.and(
            PropertyFilter.gt("age", 35), PropertyFilter.gt("height", 60), PropertyFilter.lt("height", 70)))
    .build();

Hinweise zur Indexierung

Lesen Sie die Informationen über Abfragen, bevor Sie mit dem Ausführen von Abfragen beginnen.

Wenn keine ORDER BY-Klausel angegeben ist, verwendet Firestore im Datastore-Modus einen beliebigen Index, der die Filterbedingung der Abfrage zur Bereitstellung der Abfrage erfüllen kann. Dadurch wird eine Ergebnismenge erzeugt, die gemäß der Indexdefinition geordnet ist.

Zur Optimierung der Leistung und Kosten von Firestore-Abfragen im Datastore-Modus sollten Sie die Reihenfolge der Attribute im Index optimieren. Dazu müssen Sie dafür sorgen, dass der Index von links nach rechts so geordnet ist, dass die Abfrage in ein Dataset umgewandelt wird, das das Scannen irrelevanter Indexeinträge verhindert.

Angenommen, Sie möchten eine Sammlung von Mitarbeitern durchsuchen und Mitarbeiter finden, deren Gehalt mehr als 100.000 beträgt und deren Berufserfahrung größer als 0 ist. Nach Ihrem Verständnis des Datasets wissen Sie, dass die Gehaltsbeschränkung selektiver ist als die Erfahrungsbeschränkung. Der ideale Index, bei dem die Anzahl der Indexscans reduziert werden würde, ist der Index (salary [...], experience [...]). Somit würde die schnelle und kostengünstige Abfrage salary vor experience bestellen und so aussehen:

GQL

SELECT *
FROM /employees
WHERE salary > 100000 AND experience > 0
ORDER BY salary, experience

Java

Query<Entity> query =
  Query.newEntityQueryBuilder()
    .setKind("employees")
    .setFilter(
        CompositeFilter.and(
            PropertyFilter.gt("salary", 100000), PropertyFilter.gt("experience", 0)))
    .setOrderBy(OrderBy("salary"), OrderBy("experience"))
    .build();

Node.js

const query = datastore
  .createQuery("employees")
  .filter(
    and([
      new PropertyFilter("salary", ">", 100000),
      new PropertyFilter("experience", ">", 0),
       ])
    )
  .order("salary")
  .order("experience");

Python

query = client.query(kind="employees")
query.add_filter("salary", ">", 100000)
query.add_filter("experience", ">", 0)
query.order = ["-salary", "-experience"]

Best Practices zum Optimieren von Indexen

Beachten Sie beim Optimieren von Indexen die folgenden Best Practices.

Sortieren Sie Abfragen nach Gleichheit, gefolgt vom selektiven Bereich oder Ungleichheitsfeld.

Firestore im Datastore-Modus verwendet die Attribute eines zusammengesetzten Index ganz links, um die Gleichheitseinschränkungen sowie gegebenenfalls die Bereichs- und Ungleichheitseinschränkung für das erste Feld der orderBy()-Abfrage zu erfüllen. Diese Einschränkungen können die Anzahl der Indexeinträge verringern, die Firestore im Datastore-Modus scannt. Firestore im Datastore-Modus verwendet die verbleibenden Attribute des Index, um andere Bereichs- und Ungleichheitseinschränkungen der Abfrage zu erfüllen. Diese Einschränkungen reduzieren nicht die Anzahl der Indexeinträge, die Firestore im Datastore-Modus scannt, sondern filtert nicht übereinstimmende Entitäten heraus, sodass die Anzahl der Entitäten, die an die Clients zurückgegeben werden, reduziert wird.

Weitere Informationen zum Erstellen effizienter Indexe finden Sie unter Indexstruktur und -definition und Indexe optimieren.

Attribute in absteigender Reihenfolge der Selektivität der Abfrageeinschränkung sortieren

Damit Firestore im Datastore-Modus den optimalen Index für die Abfrage auswählt, geben Sie eine orderBy()-Klausel an, die Bereichs- und Ungleichheitsattribute in absteigender Reihenfolge der Selektivität der Abfrageeinschränkung sortiert. Eine höhere Selektivität entspricht einer kleineren Teilmenge von Entitäten, während eine niedrigere Selektivität einer größeren Teilmenge von Entitäten entspricht. Achten Sie darauf, dass Sie Bereichs- und Ungleichheitsattribute mit höherer Selektivität früher in der Indexreihenfolge auswählen als Attribute mit niedriger Selektivität.

Um die Anzahl der Entitäten zu minimieren, die Firestore im Datastore-Modus scannt und über das Netzwerk zurückgibt, sollten Sie Attribute immer in absteigender Reihenfolge der Selektivität der Abfrageeinschränkung sortieren. Wenn die Ergebnismenge nicht in der erforderlichen Reihenfolge vorliegt und die Ergebnismenge voraussichtlich klein ist, können Sie clientseitige Logik implementieren, um sie entsprechend Ihren Erwartungen in Bezug auf die Reihenfolge neu anzuordnen.

Angenommen, Sie möchten in einer Sammlung von Mitarbeitenden nach Mitarbeitenden mit einem Gehalt von mehr als 100.000 suchen und die Ergebnisse nach dem Jahr der Erfahrung des Mitarbeiters sortieren. Wenn Sie davon ausgehen, dass nur eine geringe Anzahl von Mitarbeitenden ein Gehalt von mehr als 100.000 Mitarbeitern haben wird, können Sie die Abfrage so am effizientesten schreiben:

Java

Query<Entity> query =
  Query.newEntityQueryBuilder()
    .setKind("employees")
    .setFilter(PropertyFilter.gt("salary", 100000))
    .setOrderBy(OrderBy("salary"))
    .build();
QueryResults<Entity> results = datastore.run(query);
// Order results by `experience`

Node.js

const query = datastore
  .createQuery("employees")
  .filter(new PropertyFilter("salary", ">", 100000))
  .order("salary");
const [entities] = await datastore.runQuery(query);
// Order results by `experience`

Python

query = client.query(kind="employees")
query.add_filter("salary", ">", 100000)
query.order = ["salary"]
results = query.fetch()
// Order results by `experience`

Während das Hinzufügen einer Sortierung nach experience zur Abfrage den gleichen Satz von Entitäten ergibt und die Neuanordnung der Ergebnisse auf den Clients vermieden wird, kann die Abfrage viel mehr irrelevante Indexeinträge lesen als die vorherige Abfrage. Das liegt daran, dass Firestore im Datastore-Modus immer einen Index bevorzugt, dessen Indexattribute-Präfix der Reihenfolge nach Klausel der Abfrage entsprechen. Wenn experience zur Klausel „order by“ hinzugefügt wurde, wählt Firestore im Datastore-Modus den Index (experience [...], salary [...]) zur Berechnung der Abfrageergebnisse aus. Da es für experience keine anderen Einschränkungen gibt, liest Firestore im Datastore-Modus alle Indexeinträge der Sammlung employees, bevor der Filter salary angewendet wird, um den endgültigen Ergebnissatz zu finden. Das bedeutet, dass Indexeinträge, die den Filter salary nicht erfüllen, dennoch gelesen werden, wodurch sich die Latenz und die Kosten der Abfrage erhöhen.

Preise

Abfragen mit Bereichs- und Ungleichheitsfiltern für mehrere Attribute werden auf Basis der gelesenen Entitäten und Indexeinträge abgerechnet.

Ausführliche Informationen finden Sie in der Preisübersicht.

Beschränkungen

Beachten Sie neben den Abfrageeinschränkungen die folgenden Einschränkungen, bevor Sie Abfragen mit Bereichs- und Ungleichheitsfiltern für mehrere Attribute verwenden:

  • Firestore im Datastore-Modus begrenzt die Anzahl der Bereichs- oder Ungleichheitsoperatoren auf 10. Dies soll verhindern, dass Abfragen zu teuer für die Ausführung werden.

Weitere Informationen