Vista geral da indexação
Os índices são um fator importante no desempenho de uma base de dados. Tal como o índice de um livro, que mapeia os tópicos de um livro para os números das páginas, um índice de uma base de dados mapeia os itens de uma base de dados para as respetivas localizações na base de dados. Quando consulta uma base de dados, esta pode usar um índice para identificar rapidamente as localizações dos itens que pediu.
Esta página descreve os dois tipos de índices que o Firestore usa: índices de campo único e índices compostos.
Definição e estrutura do índice
Um índice é definido numa lista de campos de um determinado documento, com um modo de índice correspondente para cada campo.
Um índice contém uma entrada para cada campo com nome na definição do índice. O índice inclui todos os documentos que são os potenciais resultados para consultas baseadas no índice. Um documento só é incluído no índice se tiver um valor indexado definido para cada campo usado no índice. Se a definição do índice se referir a um campo para o qual o documento não tem nenhum valor definido, esse documento não é apresentado no índice. Neste caso, o documento nunca é devolvido como resultado de qualquer consulta baseada no índice.
O índice composto é ordenado por valores de campos, na ordem especificada na definição do índice.
Um índice por detrás de cada consulta
Se não existir um índice para uma consulta, a maioria das bases de dados analisa o respetivo conteúdo item a item, um processo lento que se torna ainda mais lento à medida que a base de dados cresce. O Firestore garante um elevado desempenho das consultas através da utilização de índices para todas as consultas. Como resultado, o desempenho da consulta depende da dimensão do conjunto de resultados e não do número de itens na base de dados.
Menos gestão de índices, mais desenvolvimento de apps
O Firestore inclui funcionalidades que reduzem o tempo que tem de dedicar à gestão de índices. Os índices necessários para as consultas mais básicas são criados automaticamente para si. À medida que usa e testa a sua app, o Firestore ajuda a identificar e criar índices adicionais de que a sua app precisa.
Tipos de índices
O Firestore usa dois tipos de índices: de campo único e compostos. Além do número de campos indexados, os índices de campo único e compostos diferem na forma como os gere.
Índices de campo único
Um índice de campo único armazena um mapeamento ordenado de todos os documentos numa coleção que contêm um campo específico. Cada entrada num índice de campo único regista o valor de um documento para um campo específico e a localização do documento na base de dados. O Firestore usa estes índices para executar muitas consultas básicas. Faz a gestão dos índices de campo único configurando as definições de indexação automática e as isenções de índice da sua base de dados.
Indexação automática
Por predefinição, o Firestore mantém automaticamente índices de campo único para cada campo num documento e cada subcampo num mapa. O Firestore usa as seguintes predefinições para índices de campo único:
Para cada campo que não seja uma matriz nem um mapa, o Firestore define dois índices de campo único ao nível da coleção, um no modo ascendente e outro no modo descendente.
Para cada campo de mapa, o Firestore cria o seguinte:
- Um índice ascendente ao nível da coleção para cada subcampo que não seja uma matriz nem um mapa.
- Um índice descendente ao nível da coleção para cada subcampo que não seja uma matriz nem um mapa.
- Um índice array-contains ao nível da coleção para cada subcampo de matriz.
- O Firestore indexa recursivamente cada subcampo do mapa.
Para cada campo de matriz num documento, o Firestore cria e mantém um índice array-contains ao nível da coleção.
Os índices de campo único com âmbito do grupo de coleções não são mantidos por predefinição.
Isenções de índice de campo único
Pode isentar um campo das definições de indexação automática criando uma isenção de índice de campo único. Uma isenção de indexação substitui as definições de índice automáticas ao nível da base de dados. Uma isenção pode ativar um índice de campo único que as suas definições de indexação automática desativariam ou desativar um índice de campo único que a indexação automática ativaria. Para casos em que as isenções podem ser úteis, consulte as práticas recomendadas de indexação.
Use o valor do caminho do campo *
para adicionar isenções de índice ao nível da coleção em todos os campos num grupo de coleções. Por exemplo, para o grupo de coleções comments
, 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. Em seguida, pode adicionar
isenções para indexar apenas os campos necessários para as suas consultas. Reduzir o número de campos indexados reduz os custos de armazenamento e pode melhorar o desempenho de escrita.
Se criar uma isenção de índice de campo único para um campo de mapa, os subcampos do mapa herdam essas definições. No entanto, pode definir isenções de índice de campo único para subcampos específicos. Se eliminar uma isenção para um subcampo, o subcampo herda as definições de isenção do respetivo campo principal, se existirem, ou as definições ao nível da base de dados se não existirem isenções principais.
Para criar e gerir isenções de índice de campo único, consulte o artigo Faça a gestão dos índices.
Índices compostos
Um índice composto armazena um mapeamento ordenado de todos os documentos numa coleção, com base numa lista ordenada de campos a indexar.
O Firestore usa índices compostos para suportar consultas que ainda não são suportadas por índices de campo único.
O Firestore não cria automaticamente índices compostos, como faz para índices de campo único, devido ao grande número de combinações de campos possíveis. Em alternativa, o Firestore ajuda a identificar e criar índices compostos necessários à medida que cria a sua app.
Sempre que tenta uma consulta que não é suportada por um índice, o Firestore devolve uma mensagem de erro com um link que pode seguir para criar o índice em falta.
Também pode definir e gerir índices compostos manualmente através da consola ou da Firebase CLI. Para mais informações sobre como criar e gerir índices compostos, consulte o artigo Faça a gestão dos índices.
Modos de índice e âmbitos de consulta
Configura os índices de campo único e compostos de forma diferente, mas ambos requerem que configure os modos de índice e os âmbitos de consulta para os seus índices.
Modos de índice
Quando define um índice, seleciona um modo de índice para cada campo indexado. O modo de índice de cada campo suporta cláusulas de consulta específicas nesse campo. Pode selecionar um dos seguintes modos de índice:
Modo de índice | Descrição |
---|---|
Ascendente | Suporta < , <= , == , >= , > , != , in e not-in , cláusulas de consulta no campo e suporta a ordenação dos resultados por ordem ascendente com base no valor deste campo. |
Descendente | Suporta as cláusulas de consulta < , <= , == , >= , > , != , in e not-in no campo e suporta a ordenação dos resultados por ordem descendente com base no valor deste campo. |
Array‑contains | Suporta as cláusulas de consulta array-contains e array-contains-any no campo. |
Vector | Suporta cláusulas de consulta FindNearest no campo. |
Âmbitos de consulta
Cada índice tem âmbito numa coleção ou num grupo de coleções. Isto é conhecido como o âmbito da consulta do índice:
- Âmbito da recolha
- O Firestore cria índices com âmbito de coleção por predefinição. Estes índices suportam consultas que devolvem resultados de uma única coleção.
- Âmbito do grupo de recolha
- Um grupo de coleções inclui todas as coleções com o mesmo ID da coleção. Para executar uma consulta de grupo de coleções que devolve resultados filtrados ou ordenados de um grupo de coleções, tem de criar um índice correspondente com âmbito do grupo de coleções.
Ordenação predefinida e o campo __name__
Além de ordenar os documentos pelos modos de índice especificados para cada campo (ascendente ou descendente) , 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. Isto significa que os documentos no conjunto de resultados com os mesmos valores de campo são ordenados pelo caminho do documento.
Por predefinição, o campo __name__
é ordenado na mesma direção do último campo ordenado na definição do índice. Por exemplo:
Coleção | Campos indexados | Âmbito da consulta |
---|---|---|
cidades | __name__ |
name, Coleção |
cidades | __name__ |
estado, Coleção |
cidades | __name__ |
país, população, Coleção |
Para ordenar os resultados pela direção __name__
não predefinida, tem de
criar esse índice.
Propriedades do índice
Um índice que permite que a consulta seja executada da forma mais eficiente é definido pelas seguintes propriedades:
- Campos usados em filtros de igualdade
- Campos usados em ordens de ordenação
- Campos usados em filtros de intervalo e desigualdade (que ainda não estão incluídos nas ordens de ordenação)
- Campos usados em agregações (que ainda não estão incluídos em ordens de ordenação e filtros de intervalo e desigualdade)
O Firestore calcula os resultados das consultas da seguinte forma:
- Identifica o índice correspondente à coleção, às propriedades de filtro, aos operadores de filtro e às ordens de ordenação da consulta.
- Identifica a posição do índice a partir da qual a análise começa. A posição inicial tem o prefixo dos filtros de igualdade da consulta e termina com os filtros de intervalo e desigualdade no primeiro campo
orderBy
. - Começa a analisar o índice, devolvendo cada documento que satisfaz todos os filtros, até que o processo de análise faça uma das seguintes ações:
- Encontra um documento que não cumpre as condições do filtro e confirma que nenhum documento subsequente vai cumprir totalmente as condições do filtro.
- Atinge o fim do índice.
- Recolhe o número máximo de resultados pedidos pela consulta.
Exemplo de indexação
Ao criar automaticamente índices de campo único, o Firestore permite que a sua aplicação suporte rapidamente as consultas de base de dados mais básicas.
Os índices de campo único permitem-lhe executar consultas simples com base nos valores dos campos e nos comparadores <
, <=
, ==
, >=
, >
e in
. Para campos de matriz, permitem-lhe executar consultas array-contains
e array-contains-any
.
Para ilustrar, examine os seguintes exemplos do ponto de vista da criação de índices. O fragmento seguinte cria alguns documentos city
numa coleção cities
e define os campos name
, state
, country
, capital
, population
e 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"] });
Partindo do princípio das predefinições de indexação automática, o Firestore atualiza um índice de campo único ascendente por campo não pertencente a uma matriz, um índice de campo único descendente por campo não pertencente a uma matriz e um índice de campo único array-contains para o campo de matriz. Cada linha na tabela seguinte representa uma entrada num índice de campo único:
Coleção | Campo indexado | Âmbito da consulta |
---|---|---|
cidades | Nome de | Coleção |
cidades | estado | Coleção |
cidades | país | Coleção |
cidades | capital | Coleção |
cidades | população | Coleção |
cidades | Nome de | 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
Com estes índices de campo único criados automaticamente, pode executar consultas simples, como as seguintes:
Web
const stateQuery = citiesRef.where("state", "==", "CA"); const populationQuery = citiesRef.where("population", "<", 100000); const nameQuery = citiesRef.where("name", ">=", "San Francisco");
Também pode criar consultas de in
e igualdade composta (==
):
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)
Se precisar de executar uma consulta composta que use uma comparação de intervalo (<
, <=
,
>
ou >=
) ou se precisar de ordenar por um campo diferente, tem de criar um
índice composto para essa consulta.
O índice array-contains
permite-lhe consultar o campo de 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 suportadas por índices compostos
O Firestore usa índices compostos para suportar consultas compostas que ainda não são suportadas por índices de campo único. Por exemplo, precisa de um índice composto para as seguintes 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 requerem o índice composto abaixo. Uma vez que a consulta usa um operador de igualdade (==
ou in
) para o campo country
, pode usar um modo de índice ascendente ou descendente para este campo. Por predefinição, as cláusulas de desigualdade aplicam uma ordem de ordenação ascendente com base no campo na cláusula de desigualdade.
Coleção | Campos indexados | Âmbito da consulta |
---|---|---|
cidades | (ou ) país, população | Coleção |
Para executar as mesmas consultas, mas com uma ordem de ordenação descendente, precisa de um índice composto adicional na direção 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")
Coleção | Campos indexados | Âmbito da consulta |
---|---|---|
cidades | país, população | Coleção |
cities | country, population | Coleção |
Para evitar a perda de desempenho causada pela união de índices, recomendamos que crie um índice composto para combinar uma consulta array-contains
ou array-contains-any
com cláusulas adicionais:
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)
Coleção | Campos indexados | Âmbito da consulta |
---|---|---|
cidades | Etiquetas array-contains, | (ou ) capitalColeção |
Consultas suportadas por índices de grupos de coleções
Para demonstrar um índice com âmbito do grupo de coleções, adicione uma subcoleção landmarks
a alguns dos documentos 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" });
Usando o seguinte índice de campo único com âmbito da coleção, pode consultar a coleção landmarks
de uma única cidade com base no campo category
:
Coleção | Campos indexados | Âmbito da consulta |
---|---|---|
pontos de referência | Categoria | (ou )Coleção |
Web
citiesRef.doc("SF").collection("landmarks").where("category", "==", "park") citiesRef.doc("SF").collection("landmarks").where("category", "in", ["park", "museum"])
Se tiver interesse em consultar os pontos de referência em todas as cidades, por exemplo,
execute esta consulta no grupo de recolha que consiste em todas as landmarks
recolhas. Também tem de ativar um landmarks
índice de campo único com âmbito do grupo de coleções:
Coleção | Campos indexados | Âmbito da consulta |
---|---|---|
pontos de referência | Categoria | (ou )Grupo de coleções |
Com este índice ativado, pode consultar o grupo de coleções landmarks
:
Web
var landmarksGroupRef = db.collectionGroup("landmarks"); landmarksGroupRef.where("category", "==", "park") landmarksGroupRef.where("category", "in", ["park", "museum"])
Para executar uma consulta de grupo de recolha que devolva resultados filtrados ou ordenados, tem de ativar um índice de campo único ou composto correspondente com âmbito do grupo de recolha. No entanto, as consultas de grupos de coleções que não filtram nem ordenam os resultados não requerem definições de índice adicionais.
Por exemplo, pode executar a seguinte consulta de grupo de recolha sem ativar um índice adicional:
Web
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 para um documento. As entradas de índice são contabilizadas para o limite de entradas de índice.
O exemplo seguinte 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
- city_name ASC
- city_name DESC
- temperatures.summer ASC
- temperatures.summer DESC
- temperatures.winter ASC
- temperatures.winter DESC
- Bairros Array Contains (ASC e DESC)
Índices compostos
- city_name ASC, neighborhoods ARRAY
- city_name DESC, neighborhoods ARRAY
Entradas de índice
Esta configuração de indexação resulta nas seguintes entradas de índice para o documento:
Índice | Dados indexados |
---|---|
Entradas de índice de campo único | |
city_name ASC | city_name: "São Francisco" |
city_name DESC | city_name: "São Francisco" |
temperatures.summer ASC | temperatures.summer: 67 |
temperatures.summer DESC | temperatures.summer: 67 |
temperatures.winter ASC | temperatures.winter: 55 |
temperatures.winter DESC | temperatures.winter: 55 |
neighborhoods Array Contains ASC | bairros: "Mission" |
neighborhoods Array Contains DESC | bairros: "Mission" |
neighborhoods Array Contains ASC | bairros: "Downtown" |
neighborhoods Array Contains DESC | bairros: "Downtown" |
neighborhoods Array Contains ASC | bairros: "Marina" |
neighborhoods Array Contains DESC | bairros: "Marina" |
Entradas de índice compostas | |
city_name ASC, neighborhoods ARRAY | city_name: "São Francisco", neighborhoods: "Mission" |
city_name ASC, neighborhoods ARRAY | city_name: "São Francisco", neighborhoods: "Downtown" |
city_name ASC, neighborhoods ARRAY | city_name: "São Francisco", neighborhoods: "Marina" |
city_name DESC, neighborhoods ARRAY | city_name: "São Francisco", neighborhoods: "Mission" |
city_name DESC, neighborhoods ARRAY | city_name: "São Francisco", neighborhoods: "Downtown" |
city_name DESC, neighborhoods ARRAY | city_name: "São Francisco", neighborhoods: "Marina" |
Índices e preços
Os índices contribuem para os custos de armazenamento da sua aplicação. Para mais informações sobre como calcular o tamanho do armazenamento para índices, consulte o artigo Tamanho da entrada do índice.
Use a união de índices
Embora o Firestore use um índice para cada consulta, não
requer necessariamente um índice por consulta. Para consultas com várias cláusulas de igualdade (==
) e, opcionalmente, uma cláusula orderBy
, o Firestore pode reutilizar índices existentes. O Firestore pode unir os índices para filtros de igualdade simples de modo a criar os índices compostos necessários para consultas de igualdade maiores.
Pode reduzir os custos de indexação identificando situações em que pode usar a união de índices. Por exemplo, numa restaurants
coleção para uma app de classificação de restaurantes:
restaurantes
burgerthyme
name : "Burger Thyme"
category : "burgers"
city : "San Francisco"
editors_pick : true
star_rating : 4
Esta app usa consultas como as seguintes. A app usa combinações de cláusulas de igualdade para category
, city
e editors_pick
, ao mesmo tempo que ordena sempre por 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")
Pode criar um índice para cada consulta:
Coleção | Campos indexados | Âmbito da consulta |
---|---|---|
restaurantes | Categoria: | , classificação por estrelas:Coleção |
restaurantes | cidade, star_rating | Coleção |
restaurantes | categoria, cidade, classificação_estrelas | Coleção |
restaurantes | category, city, editors_pick, star_rating | Coleção |
Como solução melhor, pode reduzir o número de índices tirando partido da capacidade do Firestore de unir índices para cláusulas de igualdade:
Coleção | Campos indexados | Âmbito da consulta |
---|---|---|
restaurantes | Categoria: | , classificação por estrelas:Coleção |
restaurantes | cidade, star_rating | Coleção |
restaurantes | editors_pick, star_rating | Coleção |
Este conjunto de índices não só é mais pequeno, como também suporta uma consulta adicional:
Web
db.collection("restaurants").where("editors_pick", "==", true) .orderBy("star_rating")
Limites de indexação
Os seguintes limites aplicam-se aos índices. Para mais informações sobre quotas e limites, consulte o artigo Quotas e limites.
Esta página identifica as quotas e os limites de pedidos para o Firestore.
Limite | Detalhes |
---|---|
Número máximo de índices compostos para uma base de dados |
|
Número máximo de configurações de campo único para uma base de dados |
Uma configuração ao nível do campo pode conter várias 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 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 num índice composto | 100 |
Tamanho máximo de uma entrada de índice |
7,5 KiB Para ver como o Firestore calcula o tamanho da entrada do índice, consulte o 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 |
1500 bytes Os valores dos campos com mais de 1500 bytes são truncados. As consultas que envolvem valores de campos truncados podem devolver resultados inconsistentes. |
Práticas recomendadas de indexação
Para a maioria das apps, pode confiar na indexação automática e nos links das mensagens de erro para gerir os seus índices. No entanto, pode querer adicionar isenções de campo único nos seguintes casos:
Caixa | Descrição |
---|---|
Campos de strings grandes | Se tiver um campo de string que contenha frequentemente valores de string longos que não usa para consultas, pode reduzir os custos de armazenamento isentando o campo da indexação. |
Taxas de gravação elevadas numa coleção que contém documentos com valores sequenciais | Se indexar um campo que aumenta ou diminui sequencialmente entre documentos numa coleção, como uma data/hora, a taxa de gravação máxima na coleção é de 500 gravações por segundo. Se não consultar com base no campo com valores sequenciais, pode isentar o campo da indexação para contornar este limite. Num exemplo de utilização de IoT com uma taxa de gravação elevada, uma coleção que contenha documentos com um campo de data/hora pode aproximar-se do limite de 500 gravações por segundo. |
Campos TTL |
Se usar políticas de TTL (tempo de vida), tenha em atenção que o campo TTL tem de ser uma indicação de tempo. A indexação em campos TTL está ativada por predefinição e pode afetar o desempenho a taxas de tráfego mais elevadas. Como prática recomendada, adicione isenções de campo único para os campos TTL. |
Campos de matriz ou mapa grandes | Os campos de matriz ou mapa grandes podem aproximar-se do limite de 40 000 entradas de índice por documento. Se não estiver a consultar com base num campo de matriz ou mapa grande, deve excluí-lo da indexação. |
Se estiver a usar consultas com operadores de intervalo e desigualdade em vários campos, consulte as considerações de indexação que deve ter em conta para otimizar o desempenho e o custo das consultas do Firestore
Para mais informações sobre como resolver problemas de indexação (index fanout, INVALID_ARGUMENT
errors), consulte a página de resolução de problemas.