View a markdown version of this page

Planifier les filtres de cache - Amazon DocumentDB

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Planifier les filtres de cache

Un filtre de cache de plan, également appelé filtre d'index, limite l'ensemble d'index que le planificateur de requêtes est autorisé à prendre en compte pour une forme de requête spécifique. Lorsqu'une requête correspond à une forme dotée d'un filtre, le planificateur choisit un plan uniquement parmi les index nommés dans ce filtre au lieu d'évaluer chaque index de la collection.

Une forme de requête est la combinaison du prédicat de requête, de la spécification de tri et de l'espace de noms de collection, les valeurs du prédicat étant normalisées. Deux requêtes qui ne diffèrent que par leurs valeurs partagent la même forme, de sorte qu'un seul filtre les couvre toutes. Dans la sortie deplanCacheListFilters, les valeurs normalisées sont affichées sous "@" la forme.

Un filtre de cache de plan vous permet d'épingler le plan, afin d'éviter de choisir un index plus lent en raison de la distribution des données ou de modifications d'index. Les filtres ont les propriétés suivantes :

  • Aucune modification de l'application n'est requise. Les filtres sont définis à l'aide d'une commande de base de données et appliqués sur le serveur, ce qui vous permet d'atténuer une régression sans déployer de code. C'est la principale différence par rapport à ahint, qui doit être ajouté sur chaque site d'appel.

  • La portée est une forme de requête. Une forme est définie par la collection, le prédicat et le tri, et non par la requête complète. Un filtre limite donc uniquement les requêtes qui correspondent à cette forme. Les autres requêtes concernant la même collection continuent d'être planifiées normalement.

  • Le changement est durable. Les filtres persistent lors du redémarrage de l'instance et de l'application de correctifs au moteur. La suppression de la collection entraîne la suppression de ses filtres.

  • Le changement est réversible. La suppression du filtre permet de retrouver la forme d'une planification basée sur les coûts normale. Un filtre constitue donc un moyen peu risqué de stabiliser une charge de travail pendant que vous étudiez la cause sous-jacente.

Commandes prises en charge

Les filtres de cache des plans nécessitent la version 2.0 ou ultérieure du planificateur. La commande à laquelle un filtre peut être appliqué dépend de la version du planificateur et de la version mineure d'Amazon DocumentDB, comme indiqué dans le tableau suivant.

Prise en charge des commandes pour les filtres de cache des plans
Commande Version minimale du planificateur Version mineure minimale

find

2.0

5.0.0 et 8.0.0

count

2.0

5.0.0 et 8.0.0

update

2.0

5.0.2 et 8.0.2

delete

2.0

5.0.2 et 8.0.2

findAndModify

2.0

5.0.2 et 8.0.2

distinct

3.0

8,0,0

aggregate

3.0

8,0.2

Note

La version 3.0 de Planner est disponible uniquement dans Amazon DocumentDB 8.0. Étant donné que les aggregate commandes distinct et nécessitent la version 3.0 du planificateur, les filtres de cache de plan pour ces deux commandes ne sont disponibles que dans Amazon DocumentDB 8.0. Dans Amazon DocumentDB 5.0, qui prend en charge la version 2.0 du planificateur, les filtres s'appliquent aux findAndModify commandes find count updatedelete,, et.

Pour la aggregate commande, la forme est prise depuis l'avant du pipeline : le fil $match alimente le filtre, et $sort immédiatement après il fournit le tri. $skipet $limit n'affectent pas la forme, pas plus que les étapes au-delà de ce point.

Amazon DocumentDB optimise le pipeline avant de le planifier, et un filtre de cache de plan est comparé au pipeline optimisé. Le filtre et le tri que le planificateur voit peuvent donc différer des étapes que vous avez écrites. Par exemple, deux $match étages adjacents à l'avant d'un pipeline sont combinés en un seul $and prédicat :

db.orders.aggregate([ { $match: { status: "SHIPPED" } }, { $match: { region: "us-east-1" } }, { $group: { _id: "$customerId", total: { $sum: "$amount" } } } ])

Le planificateur en voit un $match activé{$and: [{status: ...}, {region: ...}]}, le filtre doit donc être défini sur ce prédicat combiné.

db.runCommand({planCacheSetFilter: "orders", query: { $and: [ { status: "SHIPPED" }, { region: "us-east-1" } ] }, indexes: [ "status_1_region_1" ]})

Un filtre défini sur la collection étrangère d'un $graphLookup étage $lookup ou détermine l'index utilisé pour scanner cette collection étrangère.

Formes de requête prises en charge

À partir d'Amazon DocumentDB 5.0.2 et 8.0.2, les opérateurs suivants peuvent apparaître dans une forme de requête dotée d'un filtre de cache de plan :

  • $text. La chaîne de recherche est normalisée, de sorte que les requêtes qui ne diffèrent que par les termes qu'elles recherchent partagent la même forme.

  • $near et $nearSphere. Les deux opérateurs se normalisent selon la même forme. Les coordonnées$minDistance, et ne $maxDistance font pas partie de la forme.

  • $geoWithin et $geoIntersects. Le type de géométrie GeoJSON fait partie de la forme. Une Polygon requête et une MultiPolygon requête sont donc des formes différentes. Les coordonnées ne font pas partie de la forme.

  • $regex, lorsqu'il est utilisé directement sur un terrain. Le modèle et les options sont normalisés, de sorte que toutes les expressions régulières d'un même champ partagent la même forme.

La définition d'un filtre échoue avec le code d'erreur 303 pour une forme de requête qui utilise $jsonSchema$expr, ou$sampleRate. Il échoue également pour les formes suivantes. Une requête utilisant l'un d'entre eux est planifiée sans filtre :

  • Un $regex imbriqué à l'intérieur $in$nin, ou$all. Un tableau qui mélange des expressions régulières avec des valeurs littérales ne peut pas être évalué par rapport à un index, de sorte qu'un filtre sur cette forme ne pourra jamais être appliqué.

  • Une sorte de spécification de{$natural: 1}. Un $natural tri demande une analyse de la collection, ce qui est incompatible avec la restriction du planificateur à un index.

Paramétrer, répertorier et supprimer des filtres

Pour définir un filtre de cache de plan, utilisez la planCacheSetFilter commande. Les sort champs query et indiquent ensemble la forme de la requête et indexes répertorient les noms d'index que le planificateur est autorisé à prendre en compte pour cette forme.

db.runCommand({ planCacheSetFilter: <collection>, query: <query>, sort: <sort>, // optional indexes: [ <index1>, <index2>, ...], comment: <any> // optional })

Par exemple, la commande suivante limite le planificateur à l'a_1index de la forme {a: {$eq: "@"}, b: {$eq: "@"}} sans tri :

db.runCommand({planCacheSetFilter: "foo", query: { a: 1, b: 1 }, sort: {}, indexes: [ "a_1" ]})

La définition d'un filtre pour une forme qui en possède déjà un remplace le filtre existant. Après avoir exécuté les deux commandes suivantes, le filtre de la forme {a: {$eq: "@"}, b: {$eq: "@"}} est le suivant ["b_1"] :

db.runCommand({planCacheSetFilter: "foo", query: { a: 1, b: 1 }, sort: {}, indexes: [ "a_1" ]}) db.runCommand({planCacheSetFilter: "foo", query: { a: 6, b: 10 }, sort: {}, indexes: [ "b_1" ]})

Pour répertorier tous les filtres d'une collection, utilisez la planCacheListFilters commande suivante :

db.runCommand({planCacheListFilters: <collection>})

La sortie affiche chaque forme stockée avec ses valeurs normalisées et sa liste d'index autorisés :

{ "filters" : [ { "query" : { "a" : { "$eq" : "@" } }, "sort" : { }, "indexes" : [ "a_1" ] }, { "query" : { "a" : { "$gt" : "@" } }, "sort" : { "a" : 1 }, "indexes" : [ "a_1_b_1" ] } ], "ok" : 1 }

L'opérateur est préservé et seule la valeur est remplacée par"@". Une égalité implicite telle que {a: 1} est répertoriée sous sa forme explicite{"a": {"$eq": "@"}}, et les éléments d'un $in tableau sont remplacés dans leur ensemble, comme{"a": {"$in": "@"}}. Un ensemble de filtres sans tri est répertorié avec un sort document vide.

Pour supprimer des filtres, utilisez la planCacheClearFilters commande.

db.runCommand({ planCacheClearFilters: <collection>, query: <query pattern>, // optional sort: <sort specification>, // optional comment: <any> // optional })

Pour effacer tous les filtres de la collection, omettez les deux query et sort :

db.runCommand({planCacheClearFilters: "foo"})

En fournissant query les deux, vous n'sorteffacez que le filtre correspondant exactement à ce type de filtre. Les valeurs entrées query sont normalisées, de sorte que toute valeur représentative fonctionne. Pour effacer uniquement le filtre qui a été défini sans tri, transmettez un sort document vide :

db.runCommand({planCacheClearFilters: "foo", query: {a: 1}, sort: {a: 1}}) db.runCommand({planCacheClearFilters: "foo", query: {a: 1}, sort: {}})

Vérifier qu'un filtre est appliqué

La explain sortie inclut deux champs qui indiquent l'état du filtre de cache du plan :

  • indexFilterSetc'est true lorsqu'un filtre existe dans la collection pour la forme de la requête.

  • indexFilterAppliedest true uniquement lorsque la requête a été planifiée à l'aide d'un index de la liste de ce filtre.

À partir d'Amazon DocumentDB 5.0.2 et 8.0.2, ces champs sont signalés pour chaque commande prenant en charge les filtres de cache des plans, et dans la sortie du profileur pour ces commandes. Dans les versions mineures précédentes, ils n'étaient signalés que pour la find commande. Pour plus d'informations sur la lecture de la sortie Explique, consultezAnalyse du plan de requêtes.

Un filtre peut correspondre à une forme de requête sans être appliqué. Si aucun des index de la liste du filtre ne peut répondre à la requête, le planificateur replanifie sans le filtre et choisit un indice de coût. Dans ce cas, indexFilterSet c'est true et indexFilterApplied c'estfalse. Cela se produit lorsque les index nommés ne couvrent pas les champs de la requête, lorsque les index nommés n'existent pas ou lorsqu'une $regex forme ne peut pas produire de limites d'index, comme un modèle non ancré ou insensible aux majuscules et minuscules.

Exemples

Les exemples suivants utilisent une orders collection, et pour l'$lookupexemple, une customers collection avec ces index :

db.orders.createIndex({ status: 1 }) // status_1 db.orders.createIndex({ status: 1, orderDate: 1 }) // status_1_orderDate_1 db.orders.createIndex({ customerId: 1 }) // customerId_1 db.customers.createIndex({ customerId: 1 }) // customerId_1

Exemple : épingler une requête de recherche à un index composé

Prenons l'exemple d'une requête qui filtre status et trie en fonction des critères orderDate suivants :

db.orders.find({ status: "SHIPPED" }).sort({ orderDate: 1 })

L'indice composé status_1_orderDate_1 satisfait à la fois le prédicat et le tri, aucun tri distinct n'est donc nécessaire. Si le planificateur choisit plutôtstatus_1, la requête doit trier ses résultats, ce qui ajoute une SORT étape et coûte plus cher à mesure que le nombre de commandes correspondantes augmente. Pour limiter le planificateur à l'index composé de cette forme :

db.runCommand({planCacheSetFilter: "orders", query: { status: "SHIPPED" }, sort: { orderDate: 1 }, indexes: [ "status_1_orderDate_1" ]})

Comme les valeurs sont normalisées hors de la forme, ce filtre couvre également { status: "PENDING" }{ status: "CANCELLED" }, et toutes les autres valeurs de status ayant le même tri. Il ne couvre pas le même prédicat avec un tri différent, ou sans tri, qui sont des formes distinctes. Vérifiez que le filtre a pris effet en procédant comme suit explain :

db.orders.find({ status: "SHIPPED" }).sort({ orderDate: 1 }).explain()

Les rapports de sortie indexFilterSet: true etindexFilterApplied: true, ainsi que les noms des IXSCAN étapesstatus_1_orderDate_1.

Exemple : épingler une mise à jour dans un index sélectif

Une mise à jour doit localiser les documents à modifier avant de pouvoir les écrire, et cette recherche utilise un index de la même manière qu'une lecture. Lorsqu'un prédicat peut être utilisé par plusieurs index, l'index choisi par le planificateur détermine le nombre de documents examinés par la mise à jour.

db.orders.updateMany( { customerId: 4815, status: "PENDING" }, { $set: { status: "CANCELLED" } } )

Les deux customerId_1 status_1 peuvent servir ce prédicat. Pour épingler la mise à jour à customerId_1 :

db.runCommand({planCacheSetFilter: "orders", query: { customerId: 4815, status: "PENDING" }, indexes: [ "customerId_1" ]})

Les filtres sur les commandes d'écriture nécessitent Amazon DocumentDB 5.0.2 ou 8.0.2 et le planificateur version 2.0 ou ultérieure. Vérifiez à l'aide explain de l'une des mises à jour :

db.runCommand({explain: {update: "orders", updates: [{ q: { customerId: 4815, status: "PENDING" }, u: { $set: { status: "CANCELLED" } }, multi: true }]}})

Le plan gagnant est une UPDATE étape après IXSCAN l'autrecustomerId_1. Le même filtre s'applique à cette forme de requête delete et aux findAndModify commandes qui l'utilisent, car celle-ci n'inclut pas le type d'écriture.

Exemple : épingler un pipeline agrégé et une collection étrangère $lookup

Pour une agrégation, la forme est prise depuis le premier $match étage et $sort immédiatement après. Les étapes suivantes, telles que $group ou$project, ne font pas partie de la forme.

db.orders.aggregate([ { $match: { status: "SHIPPED" } }, { $group: { _id: "$customerId", total: { $sum: "$amount" } } } ])

Un filtre défini sur le $match prédicat détermine l'index utilisé pour lire : orders

db.runCommand({planCacheSetFilter: "orders", query: { status: "SHIPPED" }, indexes: [ "status_1" ]})

Les filtres s'appliquent également à la collection à laquelle appartient une $graphLookup étape $lookup ou une étape. Le filtre est défini sur la collection étrangère, et non sur la collection sur laquelle le pipeline s'exécute. Dans le pipeline suivant, orders se trouvent la collection externe et customers la collection étrangère :

db.orders.aggregate([ { $lookup: { from: "customers", localField: "customerId", foreignField: "customerId", as: "customer" } } ])

La jointure est customers sondée une fois par document externe, de sorte que l'indice choisi est appliqué à plusieurs reprises et son coût est multiplié sur l'ensemble du pipeline. Pour associer ce scan à un index spécifique, activez le filtre customers pour la forme d'égalité de la clé de jointure :

db.runCommand({planCacheSetFilter: "customers", query: { customerId: 1 }, indexes: [ "customerId_1" ]})

Comme les valeurs sont normalisées hors de la forme, la valeur 1 ci-dessus est un espace réservé et toute valeur produit le même filtre. Lorsqu'un filtre de collecte de données étrangères est appliqué, le niveau supérieur indexFilterSet et indexFilterApplied les champs sont signaléstrue, et l'indice indiquant que le filtre sélectionné apparaît du côté étranger du plan gagnant. Les filtres aggregate nécessitent Amazon DocumentDB 8.0.2 et la version 3.0 du planificateur.

Comportement avec indices et changements d'index

  • Un filtre de cache de plan a priorité sur unhint. Amazon DocumentDB applique d'abord le filtre, puis applique l'astuce dans la liste d'index autorisés du filtre. Si l'astuce désigne un index autorisé par le filtre, cet index est utilisé. Si l'astuce désigne un indice que le filtre n'autorise pas, elle est ignorée et le planificateur choisit parmi les indices autorisés en fonction des coûts. Les deux formes d'indice se comportent de la même manière, que vous donniez un nom à l'index ou que vous donniez son modèle clé.

    Par exemple, si la collection foo possède les indexa_1, b_1a_1_b_1, et que vous définissez un filtre sur la forme {query: {a: {$eq: "@"}, b: {$eq: "@"}}, sort: {a: 1}} contenant la liste d'index["a_1", "a_1_b_1"], run l'db.foo.find({ a: 10, b: 20 }).sort({a: 1}).hint({ a: 1 })utilisea_1, car il est nommé dans l'astuce et autorisé par le filtre.

  • La suppression d'un index ne modifie pas les filtres. Le filtre conserve le nom de l'index. Bien que cet index soit absent, la planification l'ignore. Si un autre index de la liste du filtre peut répondre à la requête, le filtre s'applique toujours. Ce n'est que lorsqu'aucun des index nommés n'est disponible que le indexFilterApplied rapport false est publié. La recréation d'un index portant le même nom le rend à nouveau éligible.

  • La suppression d'une collection supprime tous les filtres de cette collection.