Types d'index dans Cloud Firestore

Les index sont un facteur important dans les performances d'une base de données. Tout comme l'index d'un livre qui mappe les sujets d'un livre aux numéros de page, un index de base de données mappe les éléments d'une base de données à leurs emplacements dans la base de données. Lorsque vous envoyez une requête à une base de données, la base de données peut utiliser un index pour rechercher rapidement les emplacements des éléments que vous avez demandés.

Cette page décrit les deux types d'index qui utilise Nuage Firestore, les index mono-champ et des indices composites .

Un index derrière chaque requête

Si aucun index n'existe pour une requête, la plupart des bases de données parcourent leur contenu élément par élément, un processus lent qui ralentit encore plus à mesure que la base de données grandit. Cloud Firestore garantit la haute performance des requêtes en utilisant des index pour toutes les requêtes. Par conséquent, les performances des requêtes dépendent de la taille du jeu de résultats et non du nombre d'éléments dans la base de données.

Moins de gestion d'index, plus de développement d'applications

Cloud Firestore inclut des fonctionnalités qui réduisent le temps que vous devez consacrer à la gestion des index. Les index requis pour les requêtes les plus élémentaires sont automatiquement créés pour vous. Lorsque vous utilisez et de tester votre application, Nuage Firestore vous aide à identifier et créer des index supplémentaires votre application nécessite.

Types d'index

Cloud Firestore utilise deux types d'index: un seul champ et composite. Outre le nombre de champs indexés, les index à champ unique et composite diffèrent dans la façon dont vous les gérez.

Index à champ unique

Un index à champ unique stocke un mappage trié de tous les documents d'une collection qui contiennent un champ spécifique. Chaque entrée dans un index à champ unique enregistre la valeur d'un document pour un champ spécifique et l'emplacement du document dans la base de données. Cloud Firestore utilise ces index pour effectuer de nombreuses requêtes de base. Vous gérez les index à champ unique en configurant les paramètres d'indexation automatique et les exemptions d'index de votre base de données.

Indexation automatique

Par défaut, Cloud Firestore gère automatiquement des index à champ unique pour chaque champ d'un document et chaque sous-champ d'une carte. Cloud Firestore utilise les paramètres par défaut suivants pour les index à champ unique :

  • Pour chaque champ non-réseau et la non-map, Nuage Firestore définit deux collection de portée des index à champ unique, l' un en mode ascendant et un mode descendant.

  • Pour chaque champ de carte, Cloud Firestore crée un index ascendant de portée de collection et un index descendant pour chaque sous-champ non tableau et non carte de la carte.

  • Pour chaque champ de tableau dans un document, Cloud Firestore crée et gère un index array-contains de portée de collection.

  • Les index à champ unique avec une portée de groupe de collection ne sont pas conservés par défaut.

Exemptions d'indexation à champ unique

Vous pouvez exempter un champ de votre indexation automatique des paramètres en créant une exemption d'index unique champ. Une exemption d'indexation remplace les paramètres d'indexation automatique à l'échelle de la base de données. Une exemption peut activer un index à champ unique que vos paramètres d'indexation automatique désactiveraient ou désactiveraient un index à champ unique que l'indexation automatique permettrait autrement. Pour les cas où des dérogations peuvent être utiles, voir les meilleures pratiques d' indexation .

Si vous créez une exemption d'indexation à champ unique pour un champ de carte, les sous-champs de la carte héritent de ces paramètres. Vous pouvez toutefois définir des exemptions d'indexation à champ unique pour des sous-champs spécifiques. Si vous supprimez une exemption pour un sous-champ, le sous-champ héritera des paramètres d'exemption de son parent, s'ils existent, ou des paramètres à l'échelle de la base de données si aucune exemption parent n'existe.

Pour créer et gérer des exemptions d'index unique champ, voir Gestion des index en nuage Firestore .

Indices composites

Un index composite stocke un mappage trié de tous les documents d'une collection, sur la base d'une liste ordonnée de champs à indexer.

Cloud Firestore utilise des index composites pour prendre en charge les requêtes qui ne sont pas déjà prises en charge par les index à champ unique.

Cloud Firestore ne crée pas automatiquement des index composites comme il le fait pour les index à champ unique en raison du grand nombre de combinaisons de champs possibles. Au lieu de cela, Nuage Firestore vous aide à identifier et à créer des index composites nécessaires que vous construisez votre application.

Si vous tentez la requête ci-dessus sans créer au préalable l'index requis, Cloud Firestore renvoie un message d'erreur contenant un lien que vous pouvez suivre pour créer l'index manquant. Cela se produit chaque fois que vous tentez une requête non prise en charge par un index. Vous pouvez également définir et gérer les index composites manuellement en utilisant la console ou en utilisant le Firebase CLI . Pour en savoir plus sur la création et la gestion des indices composites, voir Gestion des index .

Modes d'indexation et étendues de requête

Vous configurez différemment les index à champ unique et les index composites, mais les deux nécessitent que vous configuriez des modes d'index et des étendues de requête pour vos index.

Modes d'indexation

Lorsque vous définissez un index, vous sélectionnez un mode d'indexation pour chaque champ indexé. Le mode d'indexation de chaque champ prend en charge des clauses de requête spécifiques sur ce champ. Vous pouvez choisir parmi les modes d'indexation suivants :

Mode index La description
croissant Supports < , <= , == , >= , > , != , in , et not-in les clauses de requête sur le terrain et les supports de tri des résultats par ordre croissant en fonction de cette valeur sur le terrain.
descendant Supports < , <= , == , >= , > , != , in , et not-in les clauses de requête sur le terrain et les supports de tri des résultats dans l' ordre décroissant en fonction de cette valeur sur le terrain.
Le tableau contient Supports array-contains et array-contains-any clauses de requête sur le terrain.

Étendues des requêtes

Chaque index est limité à une collection ou à un groupe de collections. C'est ce qu'on appelle la portée de la requête de l'index :

Portée de la collecte
Cloud Firestore crée des index avec le champ d'application de la collection par défaut. Ces index prennent en charge les requêtes qui renvoient les résultats d'une seule collection.

Portée du groupe de collecte
Un groupe de collections comprend toutes les collections avec le même ID de collection. Pour exécuter une requête de groupe de collecte que les rendements filtrés ou ordonnés résultats d'un groupe de collecte, vous devez créer un index correspondant à la portée du groupe de collecte.

Exemple d'indexation

En créant automatiquement des index à champ unique pour vous, Cloud Firestore permet à votre application de prendre en charge rapidement les requêtes de base de données les plus élémentaires. Index-champ unique vous permettent d'effectuer des requêtes simples basées sur des valeurs de champ et les comparateurs < , <= , == , >= , > , et in . Pour les champs de tableau, ils vous permettent d'effectuer array-contains et array-contains-any requêtes.

Pour illustrer, examinez les exemples suivants du point de vue de la création d'index. L'extrait suivant crée quelques city documents dans une des cities collection et définit le name , state , country , le capital , la population et les tags champs pour chaque document:

la toile
var citiesRef = db.collection("cities");

citiesRef.doc("SF").set({
    name: "San Francisco", state: "CA", country: "USA",
    capital: false, population: 860000,
    regions: ["west_coast", "norcal"] });
citiesRef.doc("LA").set({
    name: "Los Angeles", state: "CA", country: "USA",
    capital: false, population: 3900000,
    regions: ["west_coast", "socal"] });
citiesRef.doc("DC").set({
    name: "Washington, D.C.", state: null, country: "USA",
    capital: true, population: 680000,
    regions: ["east_coast"] });
citiesRef.doc("TOK").set({
    name: "Tokyo", state: null, country: "Japan",
    capital: true, population: 9000000,
    regions: ["kanto", "honshu"] });
citiesRef.doc("BJ").set({
    name: "Beijing", state: null, country: "China",
    capital: true, population: 21500000,
    regions: ["jingjinji", "hebei"] });

En supposant les paramètres d'indexation automatique par défaut, Cloud Firestore met à jour un index à champ unique croissant par champ non tableau, un index à champ unique descendant par champ non tableau et un index à champ unique contenant un tableau pour le champ tableau. Chaque ligne du tableau suivant représente une entrée dans un index à champ unique :

Collection Champ indexé Portée de la requête
villes nom Collection
villes état Collection
villes pays Collection
villes capitale Collection
villes population Collection
villes nom Collection
villes état Collection
villes pays Collection
villes capitale Collection
villes population Collection
villes array-contains les régions Collection

Requêtes prises en charge par les index à champ unique

À l'aide de ces index à champ unique créés automatiquement, vous pouvez exécuter des requêtes simples comme les suivantes :

la toile
const stateQuery = citiesRef.where("state", "==", "CA");
const populationQuery = citiesRef.where("population", "<", 100000);
const nameQuery = citiesRef.where("name", ">=", "San Francisco");

Vous pouvez également créer in et de l' égalité composé ( == ) requêtes:

la toile
citiesRef.where('country', 'in', ["USA", "Japan", "China"])

// Compound equality queries
citiesRef.where("state", "==", "CO").where("name", "==", "Denver")
citiesRef.where("country", "==", "USA")
         .where("capital", "==", false)
         .where("state", "==", "CA")
         .where("population", "==", 860000)

Si vous avez besoin d'exécuter une requête de composé qui utilise une comparaison de la plage ( < , <= , > ou >= ) ou si vous devez trier par un champ différent, vous devez créer un indice composite pour cette requête.

Le array-contains l' index vous permet d'interroger les regions champ tableau:

la toile
citiesRef.where("regions", "array-contains", "west_coast")
// array-contains-any and array-contains use the same indexes
citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"])

Requêtes prises en charge par les index composites

Cloud Firestore utilise des index composites pour prendre en charge les requêtes composées qui ne sont pas déjà prises en charge par les index à champ unique. Par exemple, vous auriez besoin d'un index composite pour les requêtes suivantes :

la toile
citiesRef.where("country", "==", "USA").orderBy("population", "asc")
citiesRef.where("country", "==", "USA").where("population", "<", 3800000)
citiesRef.where("country", "==", "USA").where("population", ">", 690000)
// in and == clauses use the same index
citiesRef.where("country", "in", ["USA", "Japan", "China"])
         .where("population", ">", 690000)

Ces requêtes nécessitent l'index composite ci-dessous. Étant donné que la requête utilise une égalité ( == ou in ) pour le country champ, vous pouvez utiliser un mode d'index par ordre croissant ou décroissant pour ce champ. Par défaut, les clauses d'inégalité appliquent un ordre de tri croissant basé sur le champ de la clause d'inégalité.

Collection Champs indexés Portée de la requête
villes (ou ) pays, population Collection

Pour exécuter les mêmes requêtes , mais avec un ordre de tri décroissant, vous avez besoin d' un indice composite supplémentaire dans le sens descendant pour la population :

la toile
citiesRef.where("country", "==", "USA").orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", "<", 3800000)
         .orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", ">", 690000)
         .orderBy("population", "desc")

citiesRef.where("country", "in", ["USA", "Japan", "China"])
         .where("population", ">", 690000)
         .orderBy("population", "desc")
Collection Champs indexés Portée de la requête
villes pays, population Collection
villes pays, population Collection

Vous devez également créer un index composite pour combiner un array-contains ou array-contains-any requête avec des clauses supplémentaires.

la toile
citiesRef.where("regions", "array-contains", "east_coast")
         .where("capital", "==", true)

// array-contains-any and array-contains use the same index
citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"])
         .where("capital", "==", true)
Collection Champs indexés Portée de la requête
villes tableau contient des balises, (ou ) Capital Collection

Requêtes prises en charge par les index de groupe de collections

Pour démontrer un indice avec la portée du groupe de collecte, imaginez que vous ajoutez un landmarks sous-collection à quelques - unes des city documents:

la toile
var citiesRef = db.collection("cities");

citiesRef.doc("SF").collection("landmarks").doc().set({
    name: "Golden Gate Bridge",
    category : "bridge" });
citiesRef.doc("SF").collection("landmarks").doc().set({
    name: "Golden Gate Park",
    category : "park" });

citiesRef.doc("DC").collection("landmarks").doc().set({
    name: "National Gallery of Art",
    category : "museum" });
citiesRef.doc("DC").collection("landmarks").doc().set({
    name: "National Mall",
    category : "park" });

En utilisant l'index un seul champ suivant avec une portée de collection, vous pouvez interroger une seule ville de landmarks de la collection en fonction de la category terrain:

Collection Champs indexés Portée de la requête
Repères (ou catégorie) Collection
la toile
citiesRef.doc("SF").collection("landmarks").where("category", "==", "park")
citiesRef.doc("SF").collection("landmarks").where("category", "in", ["park", "museum"])

Maintenant, imaginez que vous souhaitez interroger les points de repère dans toutes les villes. Pour exécuter cette requête sur le groupe de collecte composé de tous les landmarks de landmarks landmarks collections, vous devez activer un landmarks index sur un seul champ avec la portée du groupe de collection:

Collection Champs indexés Portée de la requête
Repères (ou catégorie) Groupe de collecte

Avec cet index activé, vous pouvez interroger le landmarks groupe de collection:

la toile
var landmarksGroupRef = db.collectionGroup("landmarks");

landmarksGroupRef.where("category", "==", "park")
landmarksGroupRef.where("category", "in", ["park", "museum"])

Pour exécuter une requête de groupe de collections qui renvoie des résultats filtrés ou triés, vous devez activer un index à champ unique ou composite correspondant avec une portée de groupe de collections. Cependant, les requêtes de groupe de collections qui ne filtrent ni ne trient les résultats ne nécessitent aucune définition d'index supplémentaire.

Par exemple, vous pouvez exécuter la requête de groupe de collecte suivante sans activer un index supplémentaire :

la toile
db.collectionGroup("landmarks").get()

Entrées d'index

Votre projet de les index configurés, ainsi que la structure d'un document, les deux affectent les entrées d'index pour le document, ce qui compte , finalement , vers la limite du nombre d'entrée d'index .

Voici un exemple pour illustrer.

Document

name : "San Francisco"
temperatures : {summer: 67, winter: 55}
neighborhoods : ["Mission", "Downtown", "Marina"]

Index à un seul champ

  • (Automatique) nom ASC & DESC
  • Températures (automatiques) ASC & DESC
  • Quartiers (automatiques) Tableau Contient

Indices composites

  • nom ASC, quartiers ASC
  • nom DESC, quartiers ASC

Entrées d'index résultantes

Cette configuration d'indexation génère les 12 entrées d'index suivantes pour le document :

Indice Entrée
nom ASC & DESC nom : "San Francisco"
températures ASC & DESC températures.été: 67
températures ASC & DESC températures.hiver: 55
quartiers Tableau Contient quartiers : "Mission"
quartiers Tableau Contient quartiers : "Centre-ville"
quartiers Tableau Contient quartiers : "Marina"
nom ASC, quartiers ASC nom : "San Francisco", quartiers : "Mission"
nom ASC, quartiers ASC nom : "San Francisco", quartiers : "Downtown"
nom ASC, quartiers ASC nom : "San Francisco", quartiers : "Marina"
nom DESC, quartiers ASC nom : "San Francisco", quartiers : "Mission"
nom DESC, quartiers ASC nom : "San Francisco", quartiers : "Downtown"
nom DESC, quartiers ASC nom : "San Francisco", quartiers : "Marina"

Indices et prix

Les indices contribuent aux coûts de stockage de votre application. Pour en savoir plus sur la façon dont la taille de stockage des index est calculé, voir la taille d'entrée Index .

Tirer parti de la fusion d'index

Bien que Cloud Firestore utilise un index pour chaque requête, il ne nécessite pas nécessairement un index par requête. Pour les requêtes avec de multiples égalité ( == ) les clauses et, le cas échéant, une orderBy clause, Nuage Firestore peut réutiliser les index existants. Cloud Firestore peut fusionner les index pour des filtres d'égalité simples afin de créer les index composites nécessaires pour les requêtes d'égalité plus volumineuses.

Vous pouvez réduire les coûts d'indexation en identifiant les situations dans lesquelles vous pouvez tirer parti de la fusion d'index. Par exemple, imaginez un des restaurants collection pour une application note de restaurant:

  • restaurants

    • burgerthyme

      name : "Burger Thyme"
      category : "burgers"
      city : "San Francisco"
      editors_pick : true
      star_rating : 4

Maintenant, imaginez que cette application utilise des requêtes comme celles ci-dessous. Notez que les applications utilise des combinaisons de clauses d'égalité pour la category , la city et editors_pick tout en toujours le tri par ordre croissant star_rating :

la toile
db.collection("restaurants").where("category", "==", "burgers")
                            .orderBy("star_rating")

db.collection("restaurants").where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==" "San Francisco")
                            .where("editors_pick", "==", true )
                            .orderBy("star_rating")

Vous pouvez créer un index pour chaque requête :

Collection Champs indexés Portée de la requête
Restaurants catégorie, STAR_RATING Collection
Restaurants ville, STAR_RATING Collection
Restaurants catégorie, ville, STAR_RATING Collection
Restaurants catégorie, ville, editors_pick, STAR_RATING Collection

Comme meilleure solution, vous pouvez réduire le nombre d'index en tirant parti de la capacité de Cloud Firestore à fusionner les index pour les clauses d'égalité :

Collection Champs indexés Portée de la requête
Restaurants catégorie, STAR_RATING Collection
Restaurants ville, STAR_RATING Collection
Restaurants editors_pick, STAR_RATING Collection

Non seulement cet ensemble d'index est plus petit, mais il prend également en charge une requête supplémentaire :

la toile
db.collection("restaurants").where("editors_pick", "==", true)
                            .orderBy("star_rating")

Limites d'indexation

Les limites suivantes s'appliquent aux index. Pour tous les quotas et limites, voir quotas et limites .

Limite Des détails
Nombre maximum d'index composites pour une base de données 200
Nombre maximal d'exemptions d'index à champ unique pour une base de données 200

Nombre maximum d'entrées d'index pour chaque document

40 000

Le nombre d'entrées d'index est la somme des éléments suivants pour un document :

  • Le nombre d'entrées d'index à champ unique
  • Le nombre d'entrées d'index composite

Pour voir comment Nuage Firestore transforme un document et un ensemble d'indices dans les entrées d'index, voir cet indice exemple de comptage d'entrée .

Taille maximale d'une entrée d'index

7,5 Kio

Pour voir comment Nuage Firestore calcule la taille d'entrée d'index, voir la taille d'entrée d'index .

Somme maximale des tailles des entrées d'index d'un document

8 Mio

La taille totale est la somme des éléments suivants pour un document :

  • La somme de la taille des entrées d'index à champ unique d'un document
  • La somme de la taille des entrées d'index composite d'un document
  • Taille maximale d'une valeur de champ indexée

    1500 octets

    Les valeurs de champ supérieures à 1500 octets sont tronquées. Les requêtes impliquant des valeurs de champ tronquées peuvent renvoyer des résultats incohérents.

    Indexation des bonnes pratiques

    Pour la plupart des applications, vous pouvez compter sur l'indexation automatique et les liens de message d'erreur pour gérer vos index. Cependant, vous souhaiterez peut-être ajouter des exemptions à champ unique dans les cas suivants :

    Cas La description
    Grands champs de chaîne

    Si vous avez un champ de chaîne qui contient souvent des valeurs de chaîne longues que vous n'utilisez pas pour les requêtes, vous pouvez réduire les coûts de stockage en exemptant le champ de l'indexation.

    Taux d'écriture élevés dans une collection contenant des documents avec des valeurs séquentielles

    Si vous indexez un champ qui augmente ou diminue de manière séquentielle entre les documents d'une collection, comme un horodatage, le taux d'écriture maximal dans la collection est de 500 écritures par seconde. Si vous n'interrogez pas sur la base du champ avec des valeurs séquentielles, vous pouvez exempter le champ de l'indexation pour contourner cette limite.

    Dans un cas d'utilisation IoT avec un taux d'écriture élevé, par exemple, une collection contenant des documents avec un champ d'horodatage peut approcher la limite de 500 écritures par seconde.

    Grands champs de tableau ou de carte

    Les champs de grande taille ou de carte peuvent approcher la limite de 40 000 entrées d'index par document. Si vous n'effectuez pas d'interrogation sur la base d'un grand tableau ou d'un champ de carte, vous devez l'exempter de l'indexation.