Os índices são um fator importante no desempenho de um banco de dados. Muito parecido com o índice de um livro que mapeia tópicos de um livro para números de páginas, um índice de banco de dados mapeia os itens de um banco de dados para suas localizações no banco de dados. Quando você envia uma consulta a um banco de dados, o banco de dados pode usar um índice para procurar rapidamente os locais dos itens solicitados.
Esta página descreve os dois tipos de índices usados pelo Cloud Firestore: índices de campo único e índices compostos .
Um índice por trás de cada consulta
Se não existir nenhum índice para uma consulta, a maioria dos bancos de dados rastreia seu conteúdo item por item, um processo lento que fica ainda mais lento à medida que o banco de dados cresce. O Cloud Firestore garante alto desempenho de consulta usando índices para todas as consultas. Como resultado, o desempenho da consulta depende do tamanho do conjunto de resultados e não do número de itens no banco de dados.
Menos gerenciamento de índices, mais desenvolvimento de aplicativos
O Cloud Firestore inclui recursos que reduzem o tempo gasto no gerenciamento de índices. Os índices necessários para as consultas mais básicas são criados automaticamente para você. À medida que você usa e testa seu aplicativo, o Cloud Firestore ajuda a identificar e criar índices adicionais exigidos pelo seu aplicativo.
Tipos de índice
O Cloud Firestore usa dois tipos de índices: campo único e composto . Além do número de campos indexados, os índices de campo único e compostos diferem na forma como você os gerencia.
Índices de campo único
Um índice de campo único armazena um mapeamento classificado de todos os documentos em uma coleção que contém um campo específico. Cada entrada em um índice de campo único registra o valor de um documento para um campo específico e a localização do documento no banco de dados. O Cloud Firestore usa esses índices para realizar muitas consultas básicas. Você gerencia índices de campo único definindo as configurações de indexação automática e isenções de índice do seu banco de dados.
Indexação automática
Por padrão, o Cloud Firestore mantém automaticamente índices de campo único para cada campo em um documento e cada subcampo em um mapa. O Cloud Firestore usa as seguintes configurações padrão para índices de campo único:
Para cada campo não array e não mapa, o Cloud Firestore define dois índices de campo único com escopo de coleção , um em modo ascendente e outro em modo descendente.
Para cada campo do mapa, o Cloud Firestore cria o seguinte:
- Um índice ascendente de escopo de coleção para cada subcampo não-matriz e não-mapa.
- Um índice descendente de escopo de coleção para cada subcampo não-matriz e não-mapa.
- Uma matriz de escopo de coleção contém índice para cada subcampo da matriz.
- O Cloud Firestore indexa recursivamente cada subcampo do mapa.
Para cada campo de matriz em um documento, o Cloud Firestore cria e mantém um índice contendo matriz com escopo de coleção.
Índices de campo único com escopo de grupo de coleções não são mantidos por padrão.
Isenções de índice de campo único
Você pode isentar um campo das configurações de indexação automática criando uma isenção de índice de campo único. Uma isenção de indexação substitui as configurações de indexação automática em todo o banco de dados. Uma isenção pode habilitar um índice de campo único que suas configurações de indexação automática desabilitariam ou desabilitar um índice de campo único que a indexação automática habilitaria. Para casos em que isenções podem ser úteis, consulte as melhores práticas de indexação .
Use o valor do caminho do campo *
para adicionar isenções de índice no nível da coleção em todos os campos de um grupo de coleções. Por exemplo, para comments
do grupo de coleções, defina o caminho do campo como *
para corresponder a todos os campos no grupo de coleções comments
e desative a indexação de todos os campos no grupo de coleções. Você pode então adicionar isenções para indexar apenas os campos necessários para suas consultas. A redução do número de campos indexados reduz os custos de armazenamento e pode melhorar o desempenho de gravação.
Se você criar uma isenção de índice de campo único para um campo de mapa, os subcampos do mapa herdarão essas configurações. No entanto, você pode definir isenções de índice de campo único para subcampos específicos. Se você excluir uma isenção de um subcampo, o subcampo herdará as configurações de isenção do pai, se existirem, ou as configurações de todo o banco de dados, se não existirem isenções pai.
Para criar e gerenciar isenções de índice de campo único, consulte Gerenciar índices no Cloud Firestore .
Índices compostos
Um índice composto armazena um mapeamento ordenado de todos os documentos de uma coleção, com base em uma lista ordenada de campos a serem indexados.
O Cloud Firestore usa índices compostos para dar suporte a consultas que ainda não são suportadas por índices de campo único.
O Cloud Firestore não cria índices compostos automaticamente como faz para índices de campo único devido ao grande número de combinações de campos possíveis. Em vez disso, o Cloud Firestore ajuda a identificar e criar os índices compostos necessários à medida que você cria seu aplicativo.
Se você tentar a consulta acima sem primeiro criar o índice necessário, o Cloud Firestore retornará uma mensagem de erro contendo um link que você pode seguir para criar o índice ausente. Isso acontece sempre que você tenta uma consulta não suportada por um índice. Você também pode definir e gerenciar índices compostos manualmente usando o console ou a CLI do Firebase . Para obter mais informações sobre como criar e gerenciar índices compostos, consulte Gerenciando índices .
Modos de índice e escopos de consulta
Você configura índices de campo único e compostos de maneira diferente, mas ambos exigem que você configure modos de índice e escopos de consulta para seus índices.
Modos de índice
Ao definir um índice, você seleciona um modo de índice para cada campo indexado. O modo de índice de cada campo oferece suporte a cláusulas de consulta específicas nesse campo. Você pode selecionar um dos seguintes modos de índice:
Modo de índice | Descrição |
---|---|
ascendente_para cima | Suporta < , <= , == , >= , > , != , in e not-in , cláusulas de consulta no campo e suporta a classificação de resultados em ordem crescente com base neste valor de campo. |
Seta | baixo Suporta cláusulas de consulta < , <= , == , >= , > , != , in e not-in no campo e suporta a classificação de resultados em ordem decrescente com base neste valor de campo. |
Matriz contém | Suporta cláusulas de consulta array-contains e array-contains-any no campo. |
Escopos de consulta
Cada índice tem como escopo uma coleção ou um grupo de coleções. Isso é conhecido como escopo de consulta do índice:
- Escopo da coleção
- O Cloud Firestore cria índices com escopo de coleção por padrão. Esses índices suportam consultas que retornam resultados de uma única coleção.
- Escopo do grupo de coleções
- Um grupo de coleções inclui todas as coleções com o mesmo ID de coleção. Para executar uma consulta de grupo de coleções que retorne resultados filtrados ou ordenados de um grupo de coleções, você deve criar um índice correspondente com escopo de grupo de coleções.
Ordem padrão e o campo __name__
Além de ordenar os documentos pelos modos de índice especificados para cada campo (crescente ou decrescente), os índices aplicam uma ordenação final pelo campo __name__
de cada documento. O valor do campo __name__
é definido como o caminho completo do documento. Isso significa que os documentos no conjunto de resultados com os mesmos valores de campo são classificados por caminho do documento.
Por padrão, o campo __name__
é classificado na mesma direção do último campo classificado na definição do índice. Por exemplo:
Coleção | Campos indexados | Escopo da consulta |
---|---|---|
cidades | __name__ | nome, Coleção |
cidades | estado __name__ | , Coleção |
cidades | __name__ | país, população, Coleção |
Para classificar os resultados pela direção __name__
não padrão, você precisa criar esse índice.
Exemplo de indexação
Ao criar automaticamente índices de campo único para você, o Cloud Firestore permite que seu aplicativo ofereça suporte rapidamente às consultas mais básicas do banco de dados. Os índices de campo único permitem realizar consultas simples com base nos valores dos campos e nos comparadores <
, <=
, ==
, >=
, >
, e in
. Para campos de array, eles permitem que você execute consultas array-contains
e array-contains-any
.
Para ilustrar, examine os exemplos a seguir do ponto de vista da criação de índices. O trecho a seguir cria alguns documentos city
em uma coleção cities
e define campos name
, state
, country
, capital
, population
e tags
para cada documento:
Rede
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"] });
Supondo as configurações de indexação automática padrão, o Cloud Firestore atualiza um índice de campo único ascendente por campo não-matriz, um índice de campo único descendente por campo não-matriz e um índice de campo único contendo matriz para o campo da matriz. Cada linha na tabela a seguir representa uma entrada em um índice de campo único:
Coleção | Campo indexado | Escopo da consulta |
---|---|---|
cidades | nome | Coleção |
cidades | estado | Coleção |
cidades | país | Coleção |
cidades | capital | Coleção |
cidades | população | Coleção |
cidades | nome | Coleção |
cidades | estado | Coleção |
cidades | país | Coleção |
cidades | capital | Coleção |
cidades | população | Coleção |
cidades | array-contains regiões | Coleção |
Consultas suportadas por índices de campo único
Usando esses índices de campo único criados automaticamente, você pode executar consultas simples como as seguintes:
Rede
const stateQuery = citiesRef.where("state", "==", "CA"); const populationQuery = citiesRef.where("population", "<", 100000); const nameQuery = citiesRef.where("name", ">=", "San Francisco");
Você também pode criar in
de igualdade ( ==
) e compostas:
Rede
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)
Se você precisar executar uma consulta composta que use uma comparação de intervalo ( <
, <=
, >
ou >=
) ou se precisar classificar por um campo diferente, deverá criar um índice composto para essa consulta.
O índice array-contains
permite consultar o campo da matriz regions
:
Rede
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 suportadas por índices compostos
O Cloud Firestore usa índices compostos para oferecer suporte a consultas compostas ainda não suportadas por índices de campo único. Por exemplo, você precisaria de um índice composto para as seguintes consultas:
Rede
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)
Essas consultas exigem o índice composto abaixo. Como a consulta usa uma igualdade ( ==
ou in
) para o campo country
, você pode usar um modo de índice crescente ou decrescente para esse campo. Por padrão, as cláusulas de desigualdade aplicam uma ordem de classificação crescente com base no campo da cláusula de desigualdade.
Coleção | Campos indexados | Escopo da consulta |
---|---|---|
cidades | (ou ) país, população | Coleção |
Para executar as mesmas consultas, mas com uma ordem de classificação decrescente, você precisa de um índice composto adicional na direção decrescente para population
:
Rede
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")
Coleção | Campos indexados | Escopo da consulta |
---|---|---|
cidades | país | , populaçãoColeção |
cidades | país | , populaçãoColeção |
Você também precisa criar um índice composto para combinar uma consulta array-contains
ou array-contains-any
com cláusulas adicionais.
Rede
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)
Coleção | Campos indexados | Escopo da consulta |
---|---|---|
cidades | array contém tags, | (ou ) maiúsculaColeção |
Consultas suportadas por índices de grupos de coleções
Para demonstrar um índice com escopo de grupo de coleção, imagine que você adicione uma subcoleção landmarks
a alguns dos documentos city
:
Rede
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" });
Usando o seguinte índice de campo único com escopo de coleção, você pode consultar a coleção landmarks
de uma única cidade com base no campo category
:
Coleção | Campos indexados | Escopo da consulta |
---|---|---|
pontos de referência | categoria | (ou )Coleção |
Rede
citiesRef.doc("SF").collection("landmarks").where("category", "==", "park") citiesRef.doc("SF").collection("landmarks").where("category", "in", ["park", "museum"])
Agora, imagine que você esteja interessado em consultar os pontos de referência de todas as cidades. Para executar esta consulta no grupo de coleções que consiste em todas as coleções landmarks
, você deve ativar um índice de campo único landmarks
com escopo de grupo de coleções:
Coleção | Campos indexados | Escopo da consulta |
---|---|---|
pontos de referência | categoria | (ou )Grupo de coleta |
Com este índice habilitado, você pode consultar o grupo de coleta landmarks
:
Rede
var landmarksGroupRef = db.collectionGroup("landmarks"); landmarksGroupRef.where("category", "==", "park") landmarksGroupRef.where("category", "in", ["park", "museum"])
Para executar uma consulta de grupo de coleções que retorne resultados filtrados ou ordenados, você deve ativar um campo único correspondente ou índice composto com escopo de grupo de coleções. Consultas de grupo de coleções que não filtram nem ordenam resultados, no entanto, não requerem definições de índice adicionais.
Por exemplo, você pode executar a seguinte consulta de grupo de coleções sem ativar um índice adicional:
Rede
db.collectionGroup("landmarks").get()
Entradas de índice
Os índices configurados do seu projeto e a estrutura de um documento determinam o número de entradas de índice de um documento. As entradas do índice contam para o limite de contagem de entradas do índice .
O exemplo a seguir demonstra as entradas de índice de um documento.
Documento
/cities/SF
city_name : "San Francisco"
temperatures : {summer: 67, winter: 55}
neighborhoods : ["Mission", "Downtown", "Marina"]
Índices de campo único
- nome_cidade ASC
- nome_cidade DESC
- temperaturas.verão ASC
- temperaturas.verão DESC
- temperaturas.inverno ASC
- temperaturas.inverno DESC
- Matriz de bairros contém (ASC e DESC)
Índices compostos
- city_name ASC, bairros ARRAY
- cidade_nome DESC, bairros ARRAY
Entradas de índice
Essa configuração de indexação resulta nas 18 entradas de índice a seguir para o documento:
Índice | Dados indexados |
---|---|
Entradas de índice de campo único | |
nome_cidade ASC | nome_cidade: "São Francisco" |
nome_cidade DESC | nome_cidade: "São Francisco" |
temperaturas.verão ASC | temperaturas.verão: 67 |
temperaturas.verão DESC | temperaturas.verão: 67 |
temperaturas.inverno ASC | temperaturas.inverno: 55 |
temperaturas.inverno DESC | temperaturas.inverno: 55 |
Matriz de bairros contém ASC | bairros: "Missão" |
Matriz de bairros Contém DESC | bairros: "Missão" |
Matriz de bairros contém ASC | bairros: "Centro" |
Matriz de bairros Contém DESC | bairros: "Centro" |
Matriz de bairros contém ASC | bairros: "Marina" |
Matriz de bairros Contém DESC | bairros: "Marina" |
Entradas de índice composto | |
city_name ASC, bairros ARRAY | city_name: "São Francisco", bairros: "Missão" |
city_name ASC, bairros ARRAY | city_name: "São Francisco", bairros: "Downtown" |
city_name ASC, bairros ARRAY | city_name: "São Francisco", bairros: "Marina" |
city_name DESC, bairros ARRAY | city_name: "São Francisco", bairros: "Missão" |
cidade_nome DESC, bairros ARRAY | city_name: "São Francisco", bairros: "Downtown" |
cidade_nome DESC, bairros ARRAY | city_name: "São Francisco", bairros: "Marina" |
Índices e preços
Os índices contribuem para os custos de armazenamento do seu aplicativo. Para obter mais informações sobre como o tamanho de armazenamento dos índices é calculado, consulte Tamanho da entrada do índice .
Aproveitando a fusão de índices
Embora o Cloud Firestore use um índice para cada consulta, ele não exige necessariamente um índice por consulta. Para consultas com múltiplas cláusulas de igualdade ( ==
) e, opcionalmente, uma cláusula orderBy
, o Cloud Firestore pode reutilizar índices existentes. O Cloud Firestore pode mesclar os índices de filtros de igualdade simples para criar os índices compostos necessários para consultas de igualdade maiores.
Você pode reduzir os custos de indexação identificando situações em que pode aproveitar as vantagens da fusão de índices. Por exemplo, imagine uma coleção restaurants
para um aplicativo de classificação de restaurantes:
name : "Burger Thyme"
category : "burgers"
city : "San Francisco"
editors_pick : true
star_rating : 4
Agora, imagine que este aplicativo usa consultas como as abaixo. Observe que o aplicativo usa combinações de cláusulas de igualdade para category
, city
e editors_pick
enquanto sempre classifica por ordem crescente star_rating
:
Rede
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")
Você poderia criar um índice para cada consulta:
Coleção | Campos indexados | Escopo da consulta |
---|---|---|
restaurantes | categoria | , star_ratingColeção |
restaurantes | cidade, star_rating | Coleção |
restaurantes | categoria | , cidade, star_ratingColeção |
restaurantes | categoria | , cidade , editors_pick, star_ratingColeção |
Como solução melhor, você pode reduzir o número de índices aproveitando a capacidade do Cloud Firestore de mesclar índices para cláusulas de igualdade:
Coleção | Campos indexados | Escopo da consulta |
---|---|---|
restaurantes | categoria | , star_ratingColeção |
restaurantes | cidade, star_rating | Coleção |
restaurantes | editores_pick, star_rating | Coleção |
Este conjunto de índices não é apenas menor, mas também suporta uma consulta adicional:
Rede
db.collection("restaurants").where("editors_pick", "==", true) .orderBy("star_rating")
Limites de indexação
Os limites a seguir se aplicam aos índices. Para todas as cotas e limites, consulte Cotas e Limites .
Limite | Detalhes |
---|---|
Número máximo de índices compostos para um banco de dados |
|
Número máximo de configurações de campo único para um banco de dados |
Uma configuração em nível de campo pode conter diversas configurações para o mesmo campo. Por exemplo, uma isenção de indexação de campo único e uma política de TTL no mesmo campo contam como uma configuração de campo para o limite. |
Número máximo de entradas de índice para cada documento | 40.000 O número de entradas de índice é a soma do seguinte para um documento:
Para ver como o Cloud Firestore transforma um documento e um conjunto de índices em entradas de índice, consulte este exemplo de contagem de entradas de índice . |
Número máximo de campos em um índice composto | 100 |
Tamanho máximo de uma entrada de índice | 7,5 KiB Para ver como o Cloud Firestore calcula o tamanho da entrada do índice, consulte tamanho da entrada do índice . |
Soma máxima dos tamanhos das entradas de índice de um documento | 8 MiB O tamanho total é a soma do seguinte para um documento: |
Tamanho máximo de um valor de campo indexado | 1.500 bytes Valores de campo acima de 1.500 bytes são truncados. Consultas envolvendo valores de campo truncados podem retornar resultados inconsistentes. |
Práticas recomendadas de indexação
Para a maioria dos aplicativos, você pode contar com a indexação automática e os links de mensagens de erro para gerenciar seus índices. No entanto, você pode querer adicionar isenções de campo único nos seguintes casos:
Caso | Descrição |
---|---|
Campos de string grandes | Se você tiver um campo de string que geralmente contém valores de string longos que não são usados para consulta, você poderá reduzir os custos de armazenamento isentando o campo da indexação. |
Altas taxas de gravação em uma coleção contendo documentos com valores sequenciais | Se você indexar um campo que aumenta ou diminui sequencialmente entre documentos em uma coleção, como um carimbo de data/hora, a taxa máxima de gravação na coleção será de 500 gravações por segundo. Se você não fizer a consulta com base no campo com valores sequenciais, poderá isentar o campo da indexação para contornar esse limite. Em um caso de uso de IoT com alta taxa de gravação, por exemplo, uma coleção contendo documentos com um campo de carimbo de data/hora pode se aproximar do limite de 500 gravações por segundo. |
Campos TTL | Se você usar políticas TTL (time-to-live) , observe que o campo TTL deve ser um carimbo de data/hora. A indexação em campos TTL é habilitada por padrão e pode afetar o desempenho em taxas de tráfego mais altas. Como prática recomendada, adicione isenções de campo único para seus campos TTL. |
Grande matriz ou campos de mapa | Grandes campos de array ou mapa podem atingir o limite de 40.000 entradas de índice por documento. Se você não estiver consultando com base em um array grande ou campo de mapa, deverá isentá-lo da indexação. |
Para obter mais informações sobre como resolver problemas de indexação (fanout de índice, erros INVALID_ARGUMENT
), consulte a página de solução de problemas .