Políticas de indexação no Azure Cosmos DB

APLICA-SE A: NoSQL

No Azure Cosmos DB, cada contentor tem uma política de indexação que determina como os itens do contentor devem ser indexados. A política de indexação predefinida para os contentores recém-criados indexa todas as propriedades de cada item e aplica índices de intervalo a qualquer cadeia ou número. Tal permite que obtenha um bom desempenho de consulta sem precisar de pensar na indexação e na gestão do índice antecipadamente.

Em algumas situações, poderá querer substituir este comportamento automático para se adequar melhor aos requisitos. Você pode personalizar a política de indexação de um contêiner definindo seu modo de indexação e incluir ou excluir caminhos de propriedade.

Nota

O método de atualização de políticas de indexação descrito neste artigo só se aplica à API do Azure Cosmos DB para NoSQL. Saiba mais sobre a indexação na API do Azure Cosmos DB para MongoDB

Modo de indexação

O Azure Cosmos DB dá suporte a dois modos de indexação:

  • Consistente: o índice é atualizado de forma síncrona à medida que você cria, atualiza ou exclui itens. Isso significa que a consistência de suas consultas lidas será a consistência configurada para a conta.
  • Nenhum: a indexação está desativada no contêiner. Esse modo é comumente usado quando um contêiner é usado como um armazenamento de chave-valor puro, sem a necessidade de índices secundários. Ele também pode ser usado para melhorar o desempenho de operações em massa. Após a conclusão das operações em massa, o modo de índice pode ser definido como Consistente e, em seguida, monitorado usando o IndexTransformationProgress até a conclusão.

Nota

O Azure Cosmos DB também dá suporte a um modo de indexação Lazy. A indexação em diferido executa atualizações ao índice com um nível de prioridade muito menor quando o motor não está a realizar qualquer outro trabalho. Tal poderá levar a resultados de consulta inconsistentes ou incompletos. Se você planeja consultar um contêiner do Azure Cosmos DB, não deve selecionar indexação lenta. Novos contêineres não podem selecionar indexação lenta. Você pode solicitar uma isenção entrando em contato ( cosmosdbindexing@microsoft.com exceto se estiver usando uma conta do Azure Cosmos DB no modo sem servidor que não oferece suporte à indexação lenta).

Por padrão, a política de indexação é definida como automatic. Isso é conseguido definindo a automatic propriedade na política de indexação como true. Definir essa propriedade como true permite que o Azure Cosmos DB indexe automaticamente os itens à medida que são escritos.

Tamanho do índice

No Azure Cosmos DB, o armazenamento total consumido é a combinação do tamanho dos dados e do tamanho do índice. A seguir estão algumas características do tamanho do índice:

  • O tamanho do índice depende da política de indexação. Se todas as propriedades estiverem indexadas, o tamanho do índice poderá ser maior do que o tamanho dos dados.
  • Quando os dados são excluídos, os índices são compactados quase continuamente. No entanto, para pequenas exclusões de dados, você pode não observar imediatamente uma diminuição no tamanho do índice.
  • O tamanho do índice pode crescer temporariamente quando as partições físicas se dividem. O espaço de índice é liberado depois que a divisão da partição é concluída.

Incluir e excluir os caminhos das propriedades

Uma política de indexação personalizada pode especificar caminhos de propriedade que são explicitamente incluídos ou excluídos da indexação. Ao otimizar o número de caminhos indexados, você pode reduzir substancialmente a latência e a carga de RU das operações de gravação. Esses caminhos são definidos seguindo o método descrito na seção de visão geral da indexação com as seguintes adições:

  • Um caminho que leva a um valor escalar (cadeia de caracteres ou número) termina com /?
  • elementos de uma matriz são abordados juntos através da /[] notação (em vez de /0, /1 etc.)
  • O curinga /* pode ser usado para corresponder a quaisquer elementos abaixo do nó

Tomando novamente o mesmo exemplo:

    {
        "locations": [
            { "country": "Germany", "city": "Berlin" },
            { "country": "France", "city": "Paris" }
        ],
        "headquarters": { "country": "Belgium", "employees": 250 },
        "exports": [
            { "city": "Moscow" },
            { "city": "Athens" }
        ]
    }
  • o headquarterscaminho do employees é /headquarters/employees/?

  • o locationscaminho ' country é /locations/[]/country/?

  • o caminho para qualquer coisa abaixo headquarters é /headquarters/*

Por exemplo, poderíamos incluir o /headquarters/employees/? caminho. Esse caminho garantiria que indexássemos a propriedade employees, mas não indexássemos JSON aninhado adicional dentro dessa propriedade.

Estratégia de inclusão/exclusão

Qualquer política de indexação deve incluir o caminho raiz como um caminho /* incluído ou excluído.

  • Inclua o caminho raiz para excluir seletivamente caminhos que não precisam ser indexados. Essa abordagem é recomendada, pois permite que o Azure Cosmos DB indexe proativamente qualquer nova propriedade que possa ser adicionada ao seu modelo.

  • Exclua o caminho raiz para incluir seletivamente caminhos que precisam ser indexados. O caminho da propriedade da chave de partição não é indexado por padrão com a estratégia de exclusão e deve ser explicitamente incluído, se necessário.

  • Para caminhos com caracteres regulares que incluem: caracteres alfanuméricos e _ (sublinhado), não é necessário escapar da cadeia de caracteres de caminho entre aspas duplas (por exemplo, "/path/?"). Para caminhos com outros caracteres especiais, você precisa escapar da cadeia de caracteres de caminho em torno de aspas duplas (por exemplo, "/"path-abc"/?"). Se você espera caracteres especiais em seu caminho, você pode escapar de todos os caminhos por segurança. Funcionalmente, não faz diferença se você escapar de todos os caminhos ou apenas daqueles que têm caracteres especiais.

  • A propriedade _etag system é excluída da indexação por padrão, a menos que o etag seja adicionado ao caminho incluído para indexação.

  • Se o modo de indexação estiver definido como consistente, as propriedades id do sistema serão _ts automaticamente indexadas.

  • Se não existir um caminho explicitamente indexado em um item, um valor será adicionado ao índice para indicar que o caminho está indefinido.

Todos os caminhos explicitamente incluídos terão valores adicionados ao índice para cada item no contêiner, mesmo que o caminho esteja indefinido para um determinado item.

Consulte esta seção para obter exemplos de políticas de indexação para incluir e excluir caminhos.

Incluir/excluir precedência

Se os caminhos incluídos e excluídos tiverem um conflito, o caminho mais preciso terá precedência.

Eis um exemplo:

Caminho incluído: /food/ingredients/nutrition/*

Caminho excluído: /food/ingredients/*

Nesse caso, o caminho incluído tem precedência sobre o caminho excluído porque é mais preciso. Com base nesses caminhos, quaisquer dados no food/ingredients caminho ou aninhados dentro seriam excluídos do índice. A exceção seriam os dados dentro do caminho incluído: /food/ingredients/nutrition/*, que seriam indexados.

Aqui estão algumas regras para precedência de caminhos incluídos e excluídos no Azure Cosmos DB:

  • Caminhos mais profundos são mais precisos do que caminhos mais estreitos. por exemplo: /a/b/? é mais preciso do que /a/?.

  • O /? é mais preciso do que /*. Por exemplo /a/? , é mais preciso do que /a/* isso /a/? tem precedência.

  • O caminho deve ser um caminho incluído ou um caminho /* excluído.

Índices espaciais

Ao definir um caminho espacial na política de indexação, você deve definir qual índice type deve ser aplicado a esse caminho. Os tipos possíveis de índices espaciais incluem:

  • Ponto

  • Polígono

  • Multipolígono

  • LineString

O Azure Cosmos DB, por padrão, não criará nenhum índice espacial. Se você gostaria de usar funções internas do SQL espacial, você deve criar um índice espacial nas propriedades necessárias. Consulte esta seção para obter exemplos de políticas de indexação para adicionar índices espaciais.

Índices compostos

As consultas que têm uma ORDER BY cláusula com duas ou mais propriedades exigem um índice composto. Você também pode definir um índice composto para melhorar o desempenho de muitas consultas de igualdade e intervalo. Por padrão, nenhum índice composto é definido, portanto, você deve adicionar índices compostos conforme necessário.

Ao contrário dos caminhos incluídos ou excluídos, não é possível criar um caminho com o curinga /* . Cada caminho composto tem um implícito /? no final do caminho que você não precisa especificar. Os caminhos compostos levam a um valor escalar que é o único valor incluído no índice composto. Se um caminho em um índice composto não existir em um item ou levar a um valor não escalar, um valor será adicionado ao índice para indicar que o caminho está indefinido.

Ao definir um índice composto, você especifica:

  • Dois ou mais caminhos de propriedade. A sequência na qual os caminhos de propriedade são definidos é importante.

  • A ordem (ascendente ou descendente).

Nota

Quando você adiciona um índice composto, a consulta utilizará índices de intervalo existentes até que a nova adição de índice composto seja concluída. Portanto, quando você adiciona um índice composto, você não pode observar imediatamente melhorias de desempenho. É possível acompanhar o progresso da transformação do índice usando um dos SDKs.

Consultas ORDER BY em várias propriedades:

As seguintes considerações são usadas ao usar índices compostos para consultas com uma ORDER BY cláusula com duas ou mais propriedades:

  • Se os caminhos de índice composto não corresponderem à sequência das propriedades na ORDER BY cláusula, o índice composto não poderá suportar a consulta.

  • A ordem dos caminhos de índice composto (ascendente ou descendente) também deve corresponder à orderORDER BY da cláusula.

  • O índice composto também suporta uma ORDER BY cláusula com a ordem oposta em todos os caminhos.

Considere o exemplo a seguir, onde um índice composto é definido no nome das propriedades, idade e _ts:

Índices Composto Consulta de exemplo ORDER BY Suportado pelo Índice Composto?
(name ASC, age ASC) SELECT * FROM c ORDER BY c.name ASC, c.age asc Yes
(name ASC, age ASC) SELECT * FROM c ORDER BY c.age ASC, c.name asc No
(name ASC, age ASC) SELECT * FROM c ORDER BY c.name DESC, c.age DESC Yes
(name ASC, age ASC) SELECT * FROM c ORDER BY c.name ASC, c.age DESC No
(name ASC, age ASC, timestamp ASC) SELECT * FROM c ORDER BY c.name ASC, c.age ASC, timestamp ASC Yes
(name ASC, age ASC, timestamp ASC) SELECT * FROM c ORDER BY c.name ASC, c.age ASC No

Você deve personalizar sua política de indexação para poder atender a todas as consultas necessárias ORDER BY .

Consultas com filtros em várias propriedades

Se uma consulta tiver filtros em duas ou mais propriedades, pode ser útil criar um índice composto para essas propriedades.

Por exemplo, considere a seguinte consulta que tem um filtro de igualdade e intervalo:

SELECT *
FROM c
WHERE c.name = "John" AND c.age > 18

Essa consulta será mais eficiente, levando menos tempo e consumindo menos RUs, se for capaz de alavancar um índice composto no (name ASC, age ASC).

As consultas com vários filtros de intervalo também podem ser otimizadas com um índice composto. No entanto, cada índice composto individual só pode otimizar um único filtro de intervalo. Os filtros de intervalo incluem >, , , >=<<=e .!= O filtro de intervalo deve ser definido em último lugar no índice composto.

Considere a seguinte consulta com um filtro de igualdade e dois filtros de intervalo:

SELECT *
FROM c
WHERE c.name = "John" AND c.age > 18 AND c._ts > 1612212188

Esta consulta será mais eficiente com um índice composto em (name ASC, age ASC) e (name ASC, _ts ASC). No entanto, a consulta não utilizaria um índice composto porque (age ASC, name ASC) as propriedades com filtros de igualdade devem ser definidas primeiro no índice composto. Dois índices compostos separados são necessários em vez de um único índice composto, uma vez que cada índice (name ASC, age ASC, _ts ASC) composto só pode otimizar um único filtro de intervalo.

As considerações a seguir são usadas ao criar índices compostos para consultas com filtros em várias propriedades

  • As expressões de filtro podem usar vários índices compostos.
  • As propriedades no filtro da consulta devem corresponder às do índice composto. Se uma propriedade estiver no índice composto, mas não estiver incluída na consulta como um filtro, a consulta não utilizará o índice composto.
  • Se uma consulta tiver outras propriedades no filtro que não estejam definidas em um índice composto, uma combinação de índices compostos e de intervalo será usada para avaliar a consulta. Isso exigirá menos RUs do que usar exclusivamente índices de intervalo.
  • Se uma propriedade tiver um filtro de intervalo (>, , , , >=<<=ou !=), essa propriedade deverá ser definida por último no índice composto. Se uma consulta tiver mais de um filtro de intervalo, ela poderá se beneficiar de vários índices compostos.
  • Ao criar um índice composto para otimizar consultas com vários filtros, o ORDER índice composto não terá impacto nos resultados. Esta propriedade é opcional.

Considere os seguintes exemplos em que um índice composto é definido no nome das propriedades, idade e carimbo de data/hora:

Índices Composto Consulta de exemplo Suportado pelo Índice Composto?
(name ASC, age ASC) SELECT * FROM c WHERE c.name = "John" AND c.age = 18 Yes
(name ASC, age ASC) SELECT * FROM c WHERE c.name = "John" AND c.age > 18 Yes
(name ASC, age ASC) SELECT COUNT(1) FROM c WHERE c.name = "John" AND c.age > 18 Yes
(name DESC, age ASC) SELECT * FROM c WHERE c.name = "John" AND c.age > 18 Yes
(name ASC, age ASC) SELECT * FROM c WHERE c.name != "John" AND c.age > 18 No
(name ASC, age ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" AND c.age = 18 AND c.timestamp > 123049923 Yes
(name ASC, age ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" AND c.age < 18 AND c.timestamp = 123049923 No
(name ASC, age ASC) and (name ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" AND c.age < 18 AND c.timestamp > 123049923 Yes

Consultas com filtro e ORDER BY

Se uma consulta filtra uma ou mais propriedades e tem propriedades diferentes na cláusula ORDER BY, pode ser útil adicionar as propriedades no filtro à ORDER BY cláusula.

Por exemplo, adicionando as propriedades no filtro à ORDER BY cláusula, a seguinte consulta pode ser reescrita para aproveitar um índice composto:

Consulta usando o índice de intervalo:

SELECT *
FROM c 
WHERE c.name = "John" 
ORDER BY c.timestamp

Consulta usando índice composto:

SELECT * 
FROM c 
WHERE c.name = "John"
ORDER BY c.name, c.timestamp

As mesmas otimizações de consulta podem ser generalizadas para quaisquer ORDER BY consultas com filtros, tendo em mente que índices compostos individuais só podem suportar, no máximo, um filtro de intervalo.

Consulta usando o índice de intervalo:

SELECT * 
FROM c 
WHERE c.name = "John" AND c.age = 18 AND c.timestamp > 1611947901 
ORDER BY c.timestamp

Consulta usando índice composto:

SELECT * 
FROM c 
WHERE c.name = "John" AND c.age = 18 AND c.timestamp > 1611947901 
ORDER BY c.name, c.age, c.timestamp

Além disso, você pode usar índices compostos para otimizar consultas com funções do sistema e ORDER BY:

Consulta usando o índice de intervalo:

SELECT * 
FROM c 
WHERE c.firstName = "John" AND Contains(c.lastName, "Smith", true) 
ORDER BY c.lastName

Consulta usando índice composto:

SELECT * 
FROM c 
WHERE c.firstName = "John" AND Contains(c.lastName, "Smith", true) 
ORDER BY c.firstName, c.lastName

As seguintes considerações se aplicam ao criar índices compostos para otimizar uma consulta com um filtro e ORDER BY uma cláusula:

  • Se você não definir um índice composto em uma consulta com um filtro em uma propriedade e uma cláusula separada ORDER BY usando uma propriedade diferente, a consulta ainda terá êxito. No entanto, o custo RU da consulta pode ser reduzido com um índice composto, particularmente se a ORDER BY propriedade na cláusula tiver uma cardinalidade alta.
  • Se a consulta filtrar propriedades, essas propriedades devem ser incluídas primeiro na ORDER BY cláusula.
  • Se a consulta filtra em várias propriedades, os filtros de igualdade devem ser as primeiras propriedades na ORDER BY cláusula.
  • Se a consulta filtra em várias propriedades, você pode ter no máximo um filtro de intervalo ou função do sistema utilizada por índice composto. A propriedade usada no filtro de intervalo ou na função do sistema deve ser definida em último lugar no índice composto.
  • Todas as considerações para criar índices compostos para ORDER BY consultas com várias propriedades, bem como consultas com filtros em várias propriedades, ainda se aplicam.
Índices Composto Consulta de exemplo ORDER BY Suportado pelo Índice Composto?
(name ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" ORDER BY c.name ASC, c.timestamp ASC Yes
(name ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" AND c.timestamp > 1589840355 ORDER BY c.name ASC, c.timestamp ASC Yes
(timestamp ASC, name ASC) SELECT * FROM c WHERE c.timestamp > 1589840355 AND c.name = "John" ORDER BY c.timestamp ASC, c.name ASC No
(name ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" ORDER BY c.timestamp ASC, c.name ASC No
(name ASC, timestamp ASC) SELECT * FROM c WHERE c.name = "John" ORDER BY c.timestamp ASC No
(age ASC, name ASC, timestamp ASC) SELECT * FROM c WHERE c.age = 18 and c.name = "John" ORDER BY c.age ASC, c.name ASC,c.timestamp ASC Yes
(age ASC, name ASC, timestamp ASC) SELECT * FROM c WHERE c.age = 18 and c.name = "John" ORDER BY c.timestamp ASC No

Consultas com um filtro e um agregado

Se uma consulta filtra uma ou mais propriedades e tem uma função de sistema de agregação, pode ser útil criar um índice composto para as propriedades na função de sistema de filtro e agregação. Esta otimização aplica-se às funções do sistema SUM e AVG .

As considerações a seguir se aplicam ao criar índices compostos para otimizar uma consulta com uma função de filtro e agregação do sistema.

  • Os índices compostos são opcionais ao executar consultas com agregações. No entanto, o custo de RU da consulta pode muitas vezes ser significativamente reduzido com um índice composto.
  • Se a consulta filtra em várias propriedades, os filtros de igualdade devem ser as primeiras propriedades no índice composto.
  • Você pode ter no máximo um filtro de intervalo por índice composto e ele deve estar na propriedade na função de sistema agregado.
  • A propriedade na função de sistema agregado deve ser definida em último lugar no índice composto.
  • O order (ASC ou DESC) não importa.
Índices Composto Consulta de exemplo Suportado pelo Índice Composto?
(name ASC, timestamp ASC) SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" Yes
(timestamp ASC, name ASC) SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" No
(name ASC, timestamp ASC) SELECT AVG(c.timestamp) FROM c WHERE c.name > "John" No
(name ASC, age ASC, timestamp ASC) SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" AND c.age = 25 Yes
(age ASC, timestamp ASC) SELECT AVG(c.timestamp) FROM c WHERE c.name = "John" AND c.age > 25 No

Modificando a política de indexação

A política de indexação de um contêiner pode ser atualizada a qualquer momento usando o portal do Azure ou um dos SDKs com suporte. Uma atualização da política de indexação aciona uma transformação do índice antigo para o novo, que é realizada online e in-loco (para que nenhum espaço de armazenamento adicional seja consumido durante a operação). A política de indexação antiga é transformada de forma eficiente na nova política sem afetar a disponibilidade de gravação, a disponibilidade de leitura ou a taxa de transferência provisionada no contêiner. A transformação de índice é uma operação assíncrona, e o tempo necessário para ser concluída depende da taxa de transferência provisionada, do número de itens e de seu tamanho. Se várias atualizações de política de indexação tiverem que ser feitas, é recomendável fazer todas as alterações como uma única operação para que a transformação do índice seja concluída o mais rápido possível.

Importante

A transformação de índice é uma operação que consome Unidades de Solicitação. As unidades de solicitação consumidas por uma transformação de índice não são cobradas atualmente se você estiver usando contêineres sem servidor. Essas Unidades de Solicitação serão cobradas assim que o serverless estiver disponível ao público.

Nota

Você pode acompanhar o progresso da transformação do índice no portal do Azure ou usando um dos SDKs.

Não há impacto na disponibilidade de gravação durante quaisquer transformações de índice. A transformação do índice usa suas RUs provisionadas, mas com uma prioridade menor do que suas operações ou consultas CRUD.

Não há impacto na disponibilidade de leitura ao adicionar novos caminhos indexados. As consultas só utilizarão novos caminhos indexados quando uma transformação de índice for concluída. Em outras palavras, ao adicionar um novo caminho indexado, as consultas que se beneficiam desse caminho indexado terão o mesmo desempenho antes e durante a transformação do índice. Após a conclusão da transformação do índice, o mecanismo de consulta começará a usar os novos caminhos indexados.

Ao remover caminhos indexados, você deve agrupar todas as alterações em uma transformação de política de indexação. Se você remover vários índices e fizer isso em uma única alteração de política de indexação, o mecanismo de consulta fornecerá resultados consistentes e completos em toda a transformação do índice. No entanto, se você remover índices por meio de várias alterações de política de indexação, o mecanismo de consulta não fornecerá resultados consistentes ou completos até que todas as transformações de índice sejam concluídas. A maioria dos desenvolvedores não descarta índices e, em seguida, imediatamente tenta executar consultas que utilizam esses índices, portanto, na prática, essa situação é improvável.

Quando você solta um caminho indexado, o mecanismo de consulta interromperá imediatamente o uso e fará uma verificação completa.

Nota

Sempre que possível, você deve sempre tentar agrupar várias remoções de índice em uma única modificação de política de indexação.

Importante

A remoção de um índice afeta imediatamente, enquanto a adição de um novo índice leva algum tempo, pois requer uma transformação de indexação. Ao substituir um índice por outro (por exemplo, substituindo um único índice de propriedade por um índice composto), certifique-se de adicionar o novo índice primeiro e, em seguida, aguarde a conclusão da transformação do índice antes de remover o índice anterior da política de indexação. Caso contrário, isso afetará negativamente sua capacidade de consultar o índice anterior e poderá interromper quaisquer cargas de trabalho ativas que façam referência ao índice anterior.

Políticas de indexação e TTL

O uso do recurso TTL (Time-to-Live) requer indexação. Isto significa que:

  • não é possível ativar o TTL em um contêiner onde o modo de indexação está definido como none,
  • não é possível definir o modo de indexação como Nenhum em um contêiner onde o TTL está ativado.

Para cenários em que nenhum caminho de propriedade precisa ser indexado, mas o TTL é necessário, você pode usar uma política de indexação com um modo de indexação definido como , sem caminhos incluídos e /* como consistento único caminho excluído.

Próximos passos

Leia mais sobre a indexação nos seguintes artigos: