Tipos de índice en Cloud Firestore

Los índices son un factor importante en el rendimiento de una base de datos. Al igual que el índice de un libro que asigna los temas de un libro a los números de página, un índice de base de datos asigna los elementos de una base de datos a sus ubicaciones en la base de datos. Cuando envía una consulta a una base de datos, la base de datos puede usar un índice para buscar rápidamente las ubicaciones de los elementos que solicitó.

Esta página describe los dos tipos de índices que utiliza Cloud Firestore, índices de campo único e índices compuestos .

Un índice detrás de cada consulta

Si no existe un índice para una consulta, la mayoría de las bases de datos rastrean su contenido elemento por elemento, un proceso lento que se ralentiza aún más a medida que la base de datos crece. Cloud Firestore garantiza un alto rendimiento de las consultas mediante el uso de índices para todas las consultas. Como resultado, el rendimiento de la consulta depende del tamaño del conjunto de resultados y no del número de elementos de la base de datos.

Menos gestión de índices, más desarrollo de aplicaciones

Cloud Firestore incluye funciones que reducen la cantidad de tiempo que necesita dedicar a administrar índices. Los índices necesarios para las consultas más básicas se crean automáticamente. A medida que usas y pruebas tu aplicación, Cloud Firestore te ayuda a identificar y crear índices adicionales que tu aplicación requiere.

Tipos de índice

Cloud Firestore utiliza dos tipos de índices: de campo único y compuesto . Además de la cantidad de campos indexados, los índices de campo único y compuestos difieren en la forma en que los administra.

Índices de un solo campo

Un índice de un solo campo almacena una asignación ordenada de todos los documentos de una colección que contienen un campo específico. Cada entrada en un índice de un solo campo registra el valor de un documento para un campo específico y la ubicación del documento en la base de datos. Cloud Firestore utiliza estos índices para realizar muchas consultas básicas. Los índices de un solo campo se administran configurando los ajustes de indexación automática y las exenciones de índice de su base de datos.

Indexación automática

De forma predeterminada, Cloud Firestore mantiene automáticamente índices de campo único para cada campo de un documento y cada subcampo de un mapa. Cloud Firestore usa la siguiente configuración predeterminada para índices de un solo campo:

  • Para cada campo que no es una matriz ni un mapa, Cloud Firestore define dos índices de campo único con alcance de colección , uno en modo ascendente y otro en modo descendente.

  • Para cada campo del mapa, Cloud Firestore crea lo siguiente:

    • Un índice ascendente de alcance de colección para cada subcampo que no sea de matriz ni de mapa.
    • Un índice descendente de ámbito de colección para cada subcampo que no sea de matriz ni de mapa.
    • Una matriz de alcance de colección contiene un índice para cada subcampo de la matriz.
    • Cloud Firestore indexa de forma recursiva cada subcampo del mapa.
  • Para cada campo de matriz en un documento, Cloud Firestore crea y mantiene un índice que contiene la matriz con alcance de colección.

  • Los índices de un solo campo con alcance de grupo de colección no se mantienen de forma predeterminada.

Exenciones de índice de campo único

Puede eximir un campo de su configuración de indexación automática creando una exención de índice de un solo campo. Una exención de indexación anula la configuración de indexación automática de toda la base de datos. Una exención puede habilitar un índice de un solo campo que, de otro modo, su configuración de indexación automática deshabilitaría o deshabilitar un índice de un solo campo que, de otro modo, la indexación automática habilitaría. Para los casos en los que las exenciones pueden resultar útiles, consulte las mejores prácticas de indexación .

Utilice el valor de ruta de campo * para agregar exenciones de índice a nivel de colección en todos los campos de un grupo de colección. Por ejemplo, para comments del grupo de colección, establezca la ruta del campo en * para que coincida con todos los campos del grupo de colección de comments y deshabilite la indexación de todos los campos del grupo de colección. Luego puede agregar exenciones para indexar solo los campos requeridos para sus consultas. Reducir la cantidad de campos indexados reduce los costos de almacenamiento y puede mejorar el rendimiento de escritura.

Si crea una exención de índice de un solo campo para un campo de mapa, los subcampos del mapa heredan esa configuración. Sin embargo, puede definir exenciones de índice de un solo campo para subcampos específicos. Si elimina una exención para un subcampo, el subcampo heredará la configuración de exención de su padre, si existe, o la configuración de toda la base de datos si no existen exenciones de padre.

Para crear y administrar exenciones de índices de un solo campo, consulte Administrar índices en Cloud Firestore .

Índices compuestos

Un índice compuesto almacena una asignación ordenada de todos los documentos de una colección, basándose en una lista ordenada de campos para indexar.

Cloud Firestore utiliza índices compuestos para admitir consultas que aún no son compatibles con índices de campo único.

Cloud Firestore no crea automáticamente índices compuestos como lo hace con los índices de un solo campo debido a la gran cantidad de combinaciones de campos posibles. En cambio, Cloud Firestore te ayuda a identificar y crear los índices compuestos necesarios a medida que creas tu aplicación.

Si intenta realizar la consulta anterior sin crear primero el índice requerido, Cloud Firestore devuelve un mensaje de error que contiene un enlace que puede seguir para crear el índice que falta. Esto sucede cada vez que intenta realizar una consulta que no está respaldada por un índice. También puede definir y administrar índices compuestos manualmente mediante la consola o Firebase CLI . Para obtener más información sobre la creación y gestión de índices compuestos, consulte Gestión de índices .

Modos de índice y alcances de consulta

Los índices compuestos y de campo único se configuran de manera diferente, pero ambos requieren que configure los modos de índice y los alcances de consulta para sus índices.

Modos de índice

Cuando define un índice, selecciona un modo de índice para cada campo indexado. El modo de índice de cada campo admite cláusulas de consulta específicas en ese campo. Puede seleccionar entre los siguientes modos de índice:

Modo de índice Descripción
ascendente_arriba Admite cláusulas de consulta < , <= , == , >= , > , != , in y not-in en el campo y admite la clasificación de los resultados en orden ascendente según el valor de este campo.
Flecha descendente_hacia Admite cláusulas de consulta < , <= , == , >= , > , != , in y not-in en el campo y admite la clasificación de los resultados en orden descendente según el valor de este campo.
La matriz contiene Admite cláusulas de consulta array-contains y array-contains-any en el campo.

Ámbitos de consulta

Cada índice tiene como ámbito una colección o un grupo de colecciones. Esto se conoce como alcance de consulta del índice:

Alcance de la colección
Cloud Firestore crea índices con alcance de colección de forma predeterminada. Estos índices admiten consultas que devuelven resultados de una única colección.

Alcance del grupo de colección
Un grupo de colecciones incluye todas las colecciones con el mismo ID de colección. Para ejecutar una consulta de grupo de colección que devuelva resultados filtrados u ordenados de un grupo de colección, debe crear un índice correspondiente con alcance de grupo de colección.

Orden predeterminado y el campo __name__

Además de ordenar los documentos por los modos de índice especificados para cada campo (ascendente o descendente), los índices aplican una clasificación final por el campo __name__ de cada documento. El valor del campo __name__ se establece en la ruta completa del documento. Esto significa que los documentos del conjunto de resultados con los mismos valores de campo se ordenan por ruta del documento.

De forma predeterminada, el campo __name__ se ordena en la misma dirección que el último campo ordenado en la definición del índice. Por ejemplo:

Recopilación Campos indexados Alcance de la consulta
ciudades nombre, __name__ Recopilación
ciudades estado, __name__ Recopilación
ciudades país, , __name__ Recopilación

Para ordenar los resultados por la dirección __name__ no predeterminada, debe crear ese índice.

Ejemplo de indexación

Al crear automáticamente índices de un solo campo, Cloud Firestore permite que su aplicación admita rápidamente las consultas de bases de datos más básicas. Los índices de un solo campo le permiten realizar consultas simples basadas en los valores de los campos y los comparadores < , <= , == , >= , > y in . Para los campos de matriz, le permiten realizar array-contains y array-contains-any .

Para ilustrarlo, examine los siguientes ejemplos desde el punto de vista de la creación de índices. El siguiente fragmento crea algunos documentos city en una colección de cities y establece los campos de name , state , country , capital , population y tags para cada documento:

Web
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"] });

Asumiendo la configuración de indexación automática predeterminada, Cloud Firestore actualiza un índice de campo único ascendente por campo que no es de matriz, un índice de campo único descendente por campo que no es de matriz y un índice de campo único que contiene matriz para el campo de matriz. Cada fila de la siguiente tabla representa una entrada en un índice de un solo campo:

Recopilación Campo indexado Alcance de la consulta
ciudades nombre Recopilación
ciudades Recopilación
ciudades país Recopilación
ciudades Recopilación
ciudades flecha_población Recopilación
ciudades nombre Recopilación
ciudades flecha_estado Recopilación
ciudades Recopilación
ciudades Recopilación
ciudades flecha_población Recopilación
ciudades array-contains regiones Recopilación

Consultas respaldadas por índices de un solo campo

Usando estos índices de campo único creados automáticamente, puede ejecutar consultas simples como las siguientes:

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

También puede crear consultas in igualdad compuesta ( == ):

Web
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 necesita ejecutar una consulta compuesta que utiliza una comparación de rangos ( < , <= , > o >= ) o si necesita ordenar por un campo diferente, debe crear un índice compuesto para esa consulta.

El índice array-contains le permite consultar el campo de la matriz regions :

Web
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"])

Consultas soportadas por índices compuestos.

Cloud Firestore utiliza índices compuestos para admitir consultas compuestas que aún no son compatibles con índices de campo único. Por ejemplo, necesitaría un índice compuesto para las siguientes consultas:

Web
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)

Estas consultas requieren el índice compuesto a continuación. Dado que la consulta utiliza una igualdad ( == o in ) para el campo country , puede utilizar un modo de índice ascendente o descendente para este campo. De forma predeterminada, las cláusulas de desigualdad aplican un orden de clasificación ascendente basado en el campo de la cláusula de desigualdad.

Recopilación Campos indexados Alcance de la consulta
ciudades (o ) país, población Recopilación

Para ejecutar las mismas consultas pero con un orden de clasificación descendente, necesita un índice compuesto adicional en dirección descendente para population :

Web
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")
Recopilación Campos indexados Alcance de la consulta
ciudades país, población Recopilación
ciudades flecha_país , población Recopilación

También necesita crear un índice compuesto para combinar una consulta array-contains o array-contains-any con cláusulas adicionales.

Web
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)
Recopilación Campos indexados Alcance de la consulta
ciudades matriz-contiene etiquetas, (o ) mayúscula Recopilación

Consultas respaldadas por índices de grupos de colecciones

Para demostrar un índice con alcance de grupo de colección, imagine que agrega una subcolección landmarks a algunos de los documentos de la city :

Web
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" });

Utilizando el siguiente índice de campo único con alcance de colección, puede consultar la colección landmarks de una sola ciudad según el campo category :

Recopilación Campos indexados Alcance de la consulta
puntos de referencia categoría (o ) Recopilación
Web
citiesRef.doc("SF").collection("landmarks").where("category", "==", "park")
citiesRef.doc("SF").collection("landmarks").where("category", "in", ["park", "museum"])

Ahora, imagina que estás interesado en consultar los puntos de referencia de todas las ciudades. Para ejecutar esta consulta en el grupo de colección que consta de todas las colecciones landmarks , debe habilitar un índice de campo único landmarks con alcance de grupo de colección:

Recopilación Campos indexados Alcance de la consulta
puntos de referencia categoría (o ) grupo de colección

Con este índice habilitado, puede consultar el grupo de colección landmarks :

Web
var landmarksGroupRef = db.collectionGroup("landmarks");

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

Para ejecutar una consulta de grupo de colección que devuelva resultados filtrados u ordenados, debe habilitar un índice compuesto o de campo único correspondiente con alcance de grupo de colección. Sin embargo, las consultas de grupos de colecciones que no filtran ni ordenan resultados no requieren definiciones de índice adicionales.

Por ejemplo, puede ejecutar la siguiente consulta de grupo de recopilación sin habilitar un índice adicional:

Web
db.collectionGroup("landmarks").get()

Entradas de índice

Los índices configurados de su proyecto y la estructura de un documento determinan la cantidad de entradas de índice para un documento. Las entradas del índice cuentan para el límite de recuento de entradas del índice .

El siguiente ejemplo demuestra las entradas del índice de un documento.

Documento

/cities/SF

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

Índices de campo único

  • nombre_ciudad ASC
  • nombre_ciudad DESC
  • temperaturas.verano ASC
  • temperaturas.verano DESC
  • temperaturas.invierno ASC
  • temperaturas.invierno DESC
  • La matriz de vecindarios contiene (ASC y DESC)

Índices compuestos

  • nombre_ciudad ASC, barrios ARRAY
  • nombre_ciudad DESC, barrios ARRAY

Entradas de índice

Esta configuración de indexación da como resultado las siguientes 18 entradas de índice para el documento:

Índice Datos indexados
Entradas de índice de un solo campo
nombre_ciudad ASC nombre_ciudad: "San Francisco"
nombre_ciudad DESC nombre_ciudad: "San Francisco"
temperaturas.verano ASC temperaturas.verano: 67
temperaturas.verano DESC temperaturas.verano: 67
temperaturas.invierno ASC temperaturas.invierno: 55
temperaturas.invierno DESC temperaturas.invierno: 55
La matriz de vecindarios contiene ASC. barrios: "Misión"
vecindarios La matriz contiene DESC barrios: "Misión"
La matriz de vecindarios contiene ASC. barrios: "Centro"
vecindarios La matriz contiene DESC barrios: "Centro"
La matriz de vecindarios contiene ASC. barrios: "Marina"
vecindarios La matriz contiene DESC barrios: "Marina"
Entradas de índice compuesto
nombre_ciudad ASC, barrios ARRAY nombre_ciudad: "San Francisco", barrios: "Misión"
nombre_ciudad ASC, barrios ARRAY nombre_ciudad: "San Francisco", barrios: "Centro"
nombre_ciudad ASC, barrios ARRAY nombre_ciudad: "San Francisco", barrios: "Marina"
nombre_ciudad DESC, barrios ARRAY nombre_ciudad: "San Francisco", barrios: "Misión"
nombre_ciudad DESC, barrios ARRAY nombre_ciudad: "San Francisco", barrios: "Centro"
nombre_ciudad DESC, barrios ARRAY nombre_ciudad: "San Francisco", barrios: "Marina"

Índices y precios

Los índices contribuyen a los costos de almacenamiento de su aplicación. Para obtener más información sobre cómo se calcula el tamaño de almacenamiento de los índices, consulte Tamaño de entrada del índice .

Aprovechando la fusión de índices

Aunque Cloud Firestore utiliza un índice para cada consulta, no necesariamente requiere un índice por consulta. Para consultas con múltiples cláusulas de igualdad ( == ) y, opcionalmente, una cláusula orderBy , Cloud Firestore puede reutilizar los índices existentes. Cloud Firestore puede fusionar los índices para obtener filtros de igualdad simples para crear los índices compuestos necesarios para consultas de igualdad más grandes.

Puede reducir los costos de indexación identificando situaciones en las que puede aprovechar la combinación de índices. Por ejemplo, imagine una colección restaurants para una aplicación de calificación de restaurantes:

  • restaurantes

    • hamburguesa tomillo

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

Ahora, imagina que esta aplicación utiliza consultas como las que aparecen a continuación. Tenga en cuenta que la aplicación utiliza combinaciones de cláusulas de igualdad para category , city y editors_pick mientras siempre ordena por clasificación de star_rating ascendente:

Web
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")

Podrías crear un índice para cada consulta:

Recopilación Campos indexados Alcance de la consulta
restaurantes categoría, estrella_clasificación Recopilación
restaurantes ciudad, estrella_clasificación Recopilación
restaurantes categoría, ciudad, estrella_rating Recopilación
restaurantes categoría, ciudad, editores_pick, estrella_clasificación Recopilación

Como mejor solución, puede reducir la cantidad de índices aprovechando la capacidad de Cloud Firestore para fusionar índices para cláusulas de igualdad:

Recopilación Campos indexados Alcance de la consulta
restaurantes categoría, estrella_clasificación Recopilación
restaurantes ciudad, estrella_clasificación Recopilación
restaurantes editores_pick, calificación_estrellas Recopilación

Este conjunto de índices no sólo es más pequeño, sino que también admite una consulta adicional:

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

Límites de indexación

Los siguientes límites se aplican a los índices. Para conocer todas las cuotas y límites, consulte Cuotas y límites .

Límite Detalles
Número máximo de índices compuestos para una base de datos
Número máximo de configuraciones de un solo campo para una base de datos

Una configuración a nivel de campo puede contener múltiples configuraciones para el mismo campo. Por ejemplo, una exención de indexación de un solo campo y una política TTL en el mismo campo cuentan como una configuración de campo para el límite.

Número máximo de entradas de índice para cada documento

40.000

El número de entradas de índice es la suma de lo siguiente para un documento:

  • El número de entradas de índice de un solo campo.
  • El número de entradas de índice compuesto.

Para ver cómo Cloud Firestore convierte un documento y un conjunto de índices en entradas de índice, consulta este ejemplo de recuento de entradas de índice .

Número máximo de campos en un índice compuesto 100
Tamaño máximo de una entrada de índice

7,5 KiB

Para ver cómo Cloud Firestore calcula el tamaño de la entrada del índice, consulta Tamaño de la entrada del índice .

Suma máxima de los tamaños de las entradas de índice de un documento

8 MB

El tamaño total es la suma de lo siguiente para un documento:

  • La suma del tamaño de las entradas de índice de un solo campo de un documento.
  • La suma del tamaño de las entradas del índice compuesto de un documento.
  • Tamaño máximo de un valor de campo indexado

    1500 bytes

    Los valores de campo de más de 1500 bytes se truncan. Las consultas que involucran valores de campo truncados pueden arrojar resultados inconsistentes.

    Mejores prácticas de indexación

    Para la mayoría de las aplicaciones, puede confiar en la indexación automática y en los enlaces de mensajes de error para administrar sus índices. Sin embargo, es posible que desees agregar exenciones de un solo campo en los siguientes casos:

    Caso Descripción
    Campos de cadena grandes

    Si tiene un campo de cadena que a menudo contiene valores de cadena largos que no utiliza para realizar consultas, puede reducir los costos de almacenamiento eximiendo el campo de la indexación.

    Altas tasas de escritura en una colección que contiene documentos con valores secuenciales

    Si indexa un campo que aumenta o disminuye secuencialmente entre documentos de una colección, como una marca de tiempo, entonces la velocidad máxima de escritura en la colección es de 500 escrituras por segundo. Si no realiza la consulta según el campo con valores secuenciales, puede eximir el campo de la indexación para evitar este límite.

    En un caso de uso de IoT con una alta tasa de escritura, por ejemplo, una colección que contenga documentos con un campo de marca de tiempo podría acercarse al límite de 500 escrituras por segundo.

    Campos TTL

    Si utiliza políticas TTL (tiempo de vida) , tenga en cuenta que el campo TTL debe ser una marca de tiempo. La indexación en campos TTL está habilitada de forma predeterminada y puede afectar el rendimiento a tasas de tráfico más altas. Como práctica recomendada, agregue exenciones de campo único para sus campos TTL.

    Grandes campos de matriz o mapa

    Los campos grandes de matrices o mapas pueden acercarse al límite de 40.000 entradas de índice por documento. Si no realiza una consulta basada en una matriz grande o un campo de mapa, debe eximirlo de la indexación.

    Para obtener más información sobre cómo resolver problemas de indexación (despliegue de índice, errores INVALID_ARGUMENT ), consulte la página de solución de problemas .