Beschränkungen bei Abfragen

Auf dieser Seite werden die Beschränkungen behandelt, die für Datastore-Abfragen von Google App Engine aus gelten. Die folgende Liste enthält gängige Einschränkungen, auf die Sie bei der Entwicklung von Datastore treffen werden.

Entitäten, bei denen ein in der Abfrage benanntes Attribut fehlt, werden ignoriert

Entitäten desselben Typs haben nicht unbedingt dieselben Attribute. Damit eine Entität als Abfrageergebnis genutzt werden kann, muss sie einen Wert (kann null sein) für jedes Attribut haben, das in den Filtern und Sortierfolgen der Abfrage benannt wird. Wenn die Entität diese Voraussetzung nicht erfüllt, wird sie nicht in die Indexe für die Ausführung der Abfrage aufgenommen. Sie ist dann auch nicht in den Ergebnissen enthalten.

Filterung nach nicht indexierten Attributen gibt keine Ergebnisse zurück

Eine Abfrage kann keine Attributwerte finden, die nicht indexiert sind, und kann nicht nach derartigen Attributen sortieren. Eine detaillierte Erläuterung von nicht indexierten Attributen finden Sie auf der Seite Nicht indexierte Attribute.

Ungleichheitsfilter sind auf maximal ein Attribut begrenzt

Damit nicht der gesamte Index gescannt werden muss, wird bei diesem Abfrageverfahren davon ausgegangen, dass alle potenziellen Ergebnisse einer Abfrage in dem Index nebeneinanderstehen. Aus diesem Grund dürfen in einer einzelnen Abfrage keine Ungleichheitsvergleiche (LESS_THAN, LESS_THAN_OR_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, NOT_EQUAL) für mehr als ein Attribut in allen ihren Filtern verwendet werden. Beispiel: Die folgende Abfrage ist gültig, weil beide Ungleichheitsfilter auf dasselbe Attribut angewendet werden:

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter birthYearMaxFilter =
    new FilterPredicate("birthYear", FilterOperator.LESS_THAN_OR_EQUAL, maxBirthYear);

Filter birthYearRangeFilter =
    CompositeFilterOperator.and(birthYearMinFilter, birthYearMaxFilter);

Query q = new Query("Person").setFilter(birthYearRangeFilter);

Diese Abfrage ist jedoch nicht gültig, weil sie Ungleichheitsfilter für zwei verschiedene Attribute verwendet:

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter heightMaxFilter =
    new FilterPredicate("height", FilterOperator.LESS_THAN_OR_EQUAL, maxHeight);

Filter invalidFilter = CompositeFilterOperator.and(birthYearMinFilter, heightMaxFilter);

Query q = new Query("Person").setFilter(invalidFilter);

In einer Abfrage können Gleichheitsfilter (EQUAL) für unterschiedliche Attribute mit einem oder mehreren Ungleichheitsfiltern für ein einzelnes Attribut kombiniert werden. Daher ist die folgende Abfrage gültig:

Filter lastNameFilter = new FilterPredicate("lastName", FilterOperator.EQUAL, targetLastName);

Filter cityFilter = new FilterPredicate("city", FilterOperator.EQUAL, targetCity);

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter birthYearMaxFilter =
    new FilterPredicate("birthYear", FilterOperator.LESS_THAN_OR_EQUAL, maxBirthYear);

Filter validFilter =
    CompositeFilterOperator.and(
        lastNameFilter, cityFilter, birthYearMinFilter, birthYearMaxFilter);

Query q = new Query("Person").setFilter(validFilter);

Reihenfolge der Abfrageergebnisse ist undefiniert, wenn keine Sortierfolge angegeben wird

Wenn eine Abfrage keine Sortierfolge angibt, werden die Ergebnisse in der Reihenfolge zurückgegeben, in der sie abgerufen werden. Im Laufe der Datastore-Implementierung (oder wenn sich die Indexe einer Anwendung ändern) kann sich diese Reihenfolge ändern. Müssen die Abfrageergebnisse bei Ihrer Anwendung eine bestimmte Reihenfolge aufweisen, müssen Sie diese Sortierfolge deshalb explizit in der Abfrage angeben.

Sortierfolgen werden bei Attributen mit Gleichheitsfiltern ignoriert

Abfragen, die einen Gleichheitsfilter für ein bestimmtes Attribut enthalten, ignorieren jede für dieses Attribut angegebene Sortierfolge. Dies ist eine einfache Optimierung, mit der eine unnötige Verarbeitung bei einzelwertigen Attributen vermieden wird, weil alle Ergebnisse denselben Wert für das Attribut haben und somit keine weitere Sortierung erforderlich ist. Mehrwertige Attribute hingegen können zusätzliche Werte neben dem Wert haben, der mit dem Gleichheitsfilter übereinstimmt. Weil dieser Anwendungsfall selten ist, die Anwendung der Sortierfolge teuer wäre und zusätzliche Indexe erfordern würde, ignoriert der Datastore-Abfrageplaner die Sortierfolge einfach, selbst bei einem Fall mit mehreren Werten. Dies kann dazu führen, dass Abfrageergebnisse in einer anderen Reihenfolge zurückgegeben werden, als die Sortierfolge scheinbar impliziert.

In Ungleichheitsfiltern verwendete Attribute müssen zuerst sortiert werden

Zum Abrufen aller Ergebnisse, die mit einem Ungleichheitsfilter übereinstimmen, scannt eine Abfrage den Index auf die erste Zeile, die mit dem Filter übereinstimmt, und scannt dann weiter, bis eine nicht übereinstimmende Zeile gefunden wird. Damit die aufeinanderfolgenden Zeilen die vollständige Ergebnismenge bilden, müssen sie vor allen anderen Attributen sortiert werden, und zwar nach dem Attribut, das in dem Ungleichheitsfilter verwendet wird. Wenn eine Abfrage also einen oder mehrere Ungleichheitsfilter zusammen mit einer oder mehreren Sortierfolgen angibt, muss sich die erste Sortierfolge auf dasselbe Attribut beziehen, das in den Ungleichheitsfiltern angegeben wird. Die folgende Abfrage ist eine gültige Abfrage:

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("birthYear", SortDirection.ASCENDING)
        .addSort("lastName", SortDirection.ASCENDING);

Diese Abfrage ist nicht gültig, weil sie nicht nach dem Attribut sortiert, das in dem Ungleichheitsfilter verwendet wird:

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

// Not valid. Missing sort on birthYear.
Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("lastName", SortDirection.ASCENDING);

Ebenso ist diese Abfrage nicht gültig, weil das in dem Ungleichheitsfilter verwendete Attribut nicht das erste sortierte Attribut ist:

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

// Not valid. Sort on birthYear needs to be first.
Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("lastName", SortDirection.ASCENDING)
        .addSort("birthYear", SortDirection.ASCENDING);

Das Verhalten von Attributen mit mehreren Werten kann überraschend sein

Aufgrund der Art der Indexierung können Entitäten mit mehreren Werten für dasselbe Attribut gelegentlich auf unerwartete und überraschende Weise mit Abfragefiltern und Sortierfolgen interagieren.

Wenn eine Abfrage mehrere Ungleichheitsfilter für ein bestimmtes Attribut enthält, stimmt eine Entität nur dann mit der Abfrage überein, wenn mindestens einer der individuellen Werte des Attributs alle Filter erfüllt. Wenn beispielsweise eine Entität vom Typ Widget die Werte 1 und 2 für das Attribut x hat, stimmt sie nicht mit der Abfrage überein:

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.GREATER_THAN, 1),
                new FilterPredicate("x", FilterOperator.LESS_THAN, 2)));

Jeder x-Wert der Entität erfüllt einen der Filter, aber keiner der Einzelwerte erfüllt beide Filter. Beachten Sie, dass dies nicht für Gleichheitsfilter gilt. Beispielsweise erfüllt dieselbe Entität die folgende Abfrage:

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.EQUAL, 1),
                new FilterPredicate("x", FilterOperator.EQUAL, 2)));

Dabei erfüllt keiner der individuellen x-Werte der Entität beide Filterbedingungen.

Der Operator NOT_EQUAL fungiert als Test vom Typ "Wert ist anders als". So entspricht zum Beispiel die Abfrage…

Query q = new Query("Widget").setFilter(new FilterPredicate("x", FilterOperator.NOT_EQUAL, 1));

jede Widget-Entität mit einem anderen x-Wert als 1.

In Java können Sie auch eine Abfrage wie die folgende verwenden:

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.NOT_EQUAL, 1),
                new FilterPredicate("x", FilterOperator.NOT_EQUAL, 2)));

Diese fungiert wie…

x < 1 ODER (x > 1 und < 2) ODER x > 2

Daher wird eine Widget-Entität mit den x-Werten 1, 2 und 3 ermittelt, eine Entität mit den Werten 1 und 2 jedoch nicht.

Außerdem ist die Sortierfolge für mehrwertige Attribute ungewöhnlich. Weil derartige Attribute einmal im Index für jeden eindeutigen Wert auftreten, bestimmt der erste Wert im Index die Sortierreihenfolge der Entität.

  • Wenn die Abfrageergebnisse aufsteigend sortiert werden, wird der kleinste Wert des Attributs für die Sortierung verwendet.
  • Wenn die Ergebnisse in absteigender Reihenfolge sortiert werden, wird der größte Wert für die Sortierung verwendet.
  • Andere Werte und auch die Anzahl der Werte haben keinen Einfluss auf die Sortierfolge.

Dies hat die ungewöhnliche Folge, dass eine Entität mit den Attributwerten 1 und 9 in aufsteigender und absteigender Reihenfolge vor einer Entität mit den Werten 4, 5, 6 und 7 platziert ist.

Abfragen innerhalb von Transaktionen müssen Ancestor-Filter enthalten

Datastore-Transaktionen werden nur für Entitäten ausgeführt, die zur selben Entitätengruppe gehören (Nachfolgeentitäten eines gemeinsamen Ancestors). Wegen dieser Beschränkung müssen alle innerhalb einer Transaktion ausgeführten Abfragen einen Ancestor-Filter enthalten, der einen Ancestor in derselben Entitätengruppe wie die anderen Vorgänge in der Transaktion angibt.