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 utilisés par Cloud Firestore : les index à champ unique et les index composites .
Un index derrière chaque requête
S'il n'existe aucun index 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 se développe. Cloud Firestore garantit des performances de requête élevées 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 testez votre application, Cloud Firestore vous aide à identifier et à créer les index supplémentaires dont votre application a besoin.
Types d'index
Cloud Firestore utilise deux types d'index : à champ unique et composite . Outre le nombre de champs indexés, les index à champ unique et composites 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 contenant 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-tableau et non-map, Cloud Firestore définit deux index à champ unique de portée de collection , un en mode ascendant et un en mode décroissant.
Pour chaque champ de carte, Cloud Firestore crée les éléments suivants :
- Un index ascendant de portée de collection pour chaque sous-champ non-tableau et non-carte.
- Un index décroissant de portée de collection pour chaque sous-champ non-tableau et non-carte.
- Un tableau de portée de collection contient un index pour chaque sous-champ du tableau.
- Cloud Firestore indexe de manière récursive chaque sous-champ de carte.
Pour chaque champ de tableau d'un document, Cloud Firestore crée et gère un index contenant un tableau à l'échelle de la collection.
Les index à champ unique avec portée de groupe de collecte ne sont pas conservés par défaut.
Exemptions d'index à un seul champ
Vous pouvez exempter un champ de vos paramètres d'indexation automatique en créant une exemption d'index pour un seul 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 autrement ou désactiver un index à champ unique que l'indexation automatique activerait autrement. Pour les cas où des exemptions peuvent être utiles, consultez les meilleures pratiques d'indexation .
Utilisez la valeur du chemin de champ *
pour ajouter des exemptions d'index au niveau de la collection sur tous les champs d'un groupe de collections. Par exemple, pour comments
du groupe de collecte, définissez le chemin du champ sur *
pour faire correspondre tous les champs du groupe de collecte comments
et désactivez l'indexation de tous les champs du groupe de collecte. Vous pouvez ensuite ajouter des exemptions pour indexer uniquement les champs requis pour vos requêtes. La réduction du nombre de champs indexés réduit les coûts de stockage et peut améliorer les performances d'écriture.
Si vous créez une exemption d'index de 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'index de 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 de l'ensemble de la base de données s'il n'existe aucune exemption parent.
Pour créer et gérer des exemptions d'index à champ unique, consultez Gestion des index dans Cloud Firestore .
Index composites
Un index composite stocke un mappage trié de tous les documents d'une collection, basé sur 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 d'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, Cloud Firestore vous aide à identifier et à créer les index composites requis lors de la création de 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 manuellement des index composites à l'aide de la console ou de la CLI Firebase . Pour en savoir plus sur la création et la gestion d'index composites, consultez Gestion des index .
Modes d'indexation et étendues de requête
Vous configurez différemment les index à champ unique et composites, mais les deux nécessitent que vous configuriez les modes d'index et les é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 index de chaque champ prend en charge des clauses de requête spécifiques sur ce champ. Vous pouvez sélectionner parmi les modes d'indexation suivants :
Mode index | Description |
---|---|
Flèche ascendante_vers le | Prend en charge les clauses de requête < , <= , == , >= , > , != , in et not-in , sur le champ et prend en charge le tri des résultats par ordre croissant en fonction de la valeur de ce champ. |
Descendant | Prend en charge les clauses de requête < , <= , == , >= , > , != , in et not-in sur le champ et prend en charge le tri des résultats par ordre décroissant en fonction de la valeur de ce champ. |
Le tableau contient | Prend en charge les clauses de requête array-contains et array-contains-any sur le champ. |
Portées des requêtes
Chaque index est limité à une collection ou à un groupe de collections. C'est ce qu'on appelle la portée de requête de l'index :
- Périmètre de la collecte
- Cloud Firestore crée des index avec une portée de 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 ayant le même ID de collection. Pour exécuter une requête de groupe de collections qui renvoie des résultats filtrés ou ordonnés à partir d'un groupe de collections, vous devez créer un index correspondant avec la portée du groupe de collections.
Ordre par défaut et champ __name__
En plus de trier les documents selon les modes d'index spécifiés pour chaque champ (ascendant ou décroissant), les index appliquent un tri final selon le champ __name__
de chaque document. La valeur du champ __name__
est définie sur le chemin complet du document. Cela signifie que les documents du jeu de résultats avec les mêmes valeurs de champ sont triés par chemin d'accès au document.
Par défaut, le champ __name__
est trié dans le même sens que le dernier champ trié dans la définition de l'index. Par exemple:
Collection | Champs indexés | Portée de la requête |
---|---|---|
villes | __name__ | nom, Collection |
villes | état __name__ | , Collection |
villes | __name__ | pays, population, Collection |
Pour trier les résultats selon la direction __name__
autre que celle par défaut, vous devez créer cet index.
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. Les index à champ unique vous permettent d'effectuer des requêtes simples basées sur les valeurs de champ et les comparateurs <
, <=
, ==
, >=
, >
et in
. Pour les champs de tableau, ils vous permettent d'effectuer des requêtes array-contains
et array-contains-any
.
Pour illustrer, examinez les exemples suivants du point de vue de la création d’index. L'extrait suivant crée quelques documents city
dans une collection cities
et définit les champs name
, state
, country
, capital
, population
et tags
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 de champ unique ascendant par champ non-matrice, un index de champ unique décroissant par champ non-matrice et un index de champ unique contenant un tableau pour le champ du 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 | majuscule | Collection |
villes | population | Collection |
villes | nom | Collection |
villes | état | Collection |
villes | pays | Collection |
villes | majuscule | Collection |
villes | population | Collection |
villes | array-contains des 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 celles-ci :
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 des requêtes in
et composées d'égalité ( ==
) :
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 devez exécuter une requête composée qui utilise une comparaison de plages ( <
, <=
, >
ou >=
) ou si vous devez trier selon un champ différent, vous devez créer un index composite pour cette requête.
L'index array-contains
vous permet d'interroger le champ du tableau regions
:
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 champ country
, vous pouvez utiliser un mode d'indexation ascendant ou décroissant pour ce champ. Par défaut, les clauses d'inégalité appliquent un ordre de tri croissant en fonction du 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 index composite supplémentaire dans le sens décroissant pour 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 une requête array-contains
ou array-contains-any
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 ) majusculeCollection |
Requêtes prises en charge par les index de groupes de collections
Pour illustrer un index avec une portée de groupe de collections, imaginez que vous ajoutiez une sous-collection landmarks
à certains documents de la city
:
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" });
À l’aide de l’index à champ unique suivant avec portée de collection, vous pouvez interroger la collection landmarks
d’une seule ville en fonction du champ category
:
Collection | Champs indexés | Portée de la requête |
---|---|---|
Repères | catégorie | (ou )Collection |
la toile
citiesRef.doc("SF").collection("landmarks").where("category", "==", "park") citiesRef.doc("SF").collection("landmarks").where("category", "in", ["park", "museum"])
Imaginez maintenant que vous souhaitiez interroger les points de repère de toutes les villes. Pour exécuter cette requête sur le groupe de collections composé de toutes les collections landmarks
, vous devez activer un index landmarks
à champ unique avec une portée de groupe de collections :
Collection | Champs indexés | Portée de la requête |
---|---|---|
Repères | catégorie | (ou )Groupe de collecte |
Avec cet index activé, vous pouvez interroger le groupe de collecte landmarks
:
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 collecte qui renvoie des résultats filtrés ou ordonnés, vous devez activer un index composite ou à champ unique correspondant avec une étendue de groupe de collecte. Toutefois, les requêtes de groupe de collecte qui ne filtrent ni n’ordonnent 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 d'index supplémentaire :
la toile
db.collectionGroup("landmarks").get()
Entrées d'index
Les index configurés de votre projet et la structure d'un document déterminent le nombre d'entrées d'index pour un document. Les entrées d'index sont prises en compte dans la limite du nombre d'entrées d'index .
L'exemple suivant illustre les entrées d'index d'un document.
Document
/cities/SF
city_name : "San Francisco"
temperatures : {summer: 67, winter: 55}
neighborhoods : ["Mission", "Downtown", "Marina"]
Index à champ unique
- nom_ville ASC
- nom_ville DESC
- températures.été ASC
- températures.été DESC
- températures.hiver ASC
- températures.hiver DESC
- quartiers que le tableau contient (ASC et DESC)
Index composites
- city_name ASC, quartiers ARRAY
- city_name DESC, quartiers ARRAY
Entrées d'index
Cette configuration d'indexation génère les 18 entrées d'index suivantes pour le document :
Indice | Données indexées |
---|---|
Entrées d'index à champ unique | |
nom_ville ASC | nom_ville : "San Francisco" |
nom_ville DESC | nom_ville : "San Francisco" |
températures.été ASC | températures été: 67 |
températures.été DESC | températures été: 67 |
températures.hiver ASC | températures hiver: 55 |
températures.hiver DESC | températures hiver: 55 |
Le tableau de quartiers contient des ASC | quartiers : "Mission" |
quartiers Le tableau contient DESC | quartiers : "Mission" |
Le tableau de quartiers contient des ASC | quartiers : « Centre-ville » |
quartiers Le tableau contient DESC | quartiers : « Centre-ville » |
Le tableau de quartiers contient des ASC | quartiers : "Marina" |
quartiers Le tableau contient DESC | quartiers : "Marina" |
Entrées d'index composite | |
city_name ASC, quartiers ARRAY | city_name : "San Francisco", quartiers : "Mission" |
city_name ASC, quartiers ARRAY | city_name : "San Francisco", quartiers : "Downtown" |
city_name ASC, quartiers ARRAY | nom_ville : "San Francisco", quartiers : "Marina" |
city_name DESC, quartiers ARRAY | city_name : "San Francisco", quartiers : "Mission" |
city_name DESC, quartiers ARRAY | city_name : "San Francisco", quartiers : "Downtown" |
city_name DESC, quartiers ARRAY | nom_ville : "San Francisco", quartiers : "Marina" |
Indices et tarifs
Les index 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ée, consultez Taille de l'entrée d'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 plusieurs clauses d'égalité ( ==
) et, éventuellement, une clause orderBy
, Cloud 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 aux 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 une collection restaurants
pour une application d'évaluation de restaurants :
burger
thymname : "Burger Thyme"
category : "burgers"
city : "San Francisco"
editors_pick : true
star_rating : 4
Imaginez maintenant que cette application utilise des requêtes comme celles ci-dessous. Notez que l'application utilise des combinaisons de clauses d'égalité category
, city
et editors_pick
tout en triant toujours par star_rating
ascendant :
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_ratingCollection |
Restaurants | ville, star_rating | Collection |
Restaurants | catégorie | , ville , star_ratingCollection |
Restaurants | catégorie | , ville , editors_pick, star_ratingCollection |
Une meilleure solution consiste à réduire le nombre d'index en tirant parti de la capacité de Cloud Firestore à fusionner des index pour les clauses d'égalité :
Collection | Champs indexés | Portée de la requête |
---|---|---|
Restaurants | catégorie | , star_ratingCollection |
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 | Détails |
---|---|
Nombre maximum d'index composites pour une base de données |
|
Nombre maximum de configurations à champ unique pour une base de données |
Une configuration au niveau du champ peut contenir plusieurs configurations pour le même champ. Par exemple, une exemption d'indexation sur un seul champ et une politique TTL sur le même champ comptent comme une configuration de champ dans la limite. |
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 :
Pour voir comment Cloud Firestore transforme un document et un ensemble d'index en entrées d'index, consultez cet exemple de nombre d'entrées d'index . |
Nombre maximum de champs dans un index composite | 100 |
Taille maximale d'une entrée d'index | 7,5 Ko Pour voir comment Cloud Firestore calcule la taille de l'entrée d'index, consultez taille de l'entrée d'index . |
Somme maximale des tailles des entrées d'index d'un document | 8 Mo La taille totale est la somme des éléments suivants pour un document : |
Taille maximale d'une valeur de champ indexé | 1500 octets Les valeurs de champ supérieures à 1 500 octets sont tronquées. Les requêtes impliquant des valeurs de champ tronquées peuvent renvoyer des résultats incohérents. |
Meilleures pratiques d’indexation
Pour la plupart des applications, vous pouvez compter sur l'indexation automatique et les liens de messages d'erreur pour gérer vos index. Cependant, vous souhaiterez peut-être ajouter des exemptions pour un seul champ dans les cas suivants :
Cas | Description |
---|---|
Grands champs de chaînes | Si vous disposez d'un champ de chaîne contenant 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'effectuez pas de requête basée sur le 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. |
Champs TTL | Si vous utilisez des politiques TTL (durée de vie) , notez que le champ TTL doit être un horodatage. L'indexation sur les champs TTL est activée par défaut et peut affecter les performances à des taux de trafic plus élevés. Il est recommandé d'ajouter des exemptions pour un seul champ à vos champs TTL. |
Grands champs de tableau ou de carte | Les grands champs de tableau ou de carte peuvent approcher la limite de 40 000 entrées d’index par document. Si vous n'effectuez pas de requête sur la base d'un grand tableau ou d'un champ de carte, vous devez l'exempter de l'indexation. |
Pour plus d'informations sur la façon de résoudre les problèmes d'indexation (panout d'index, erreurs INVALID_ARGUMENT
), consultez la page de dépannage .