Share via


Ajustando o desempenho de consulta com o Azure Cosmos DB

APLICA-SE A: NoSQL

O Azure Cosmos DB fornece uma API para NoSQL para consultar dados, sem a necessidade de esquema ou índices secundários. Este artigo fornece as seguintes informações para desenvolvedores:

  • Detalhes de alto nível sobre como funciona a execução da consulta SQL do Azure Cosmos DB
  • Algumas dicas e práticas recomendadas para desempenho de consulta
  • Exemplos de como utilizar métricas de execução de consultas SQL para depurar o desempenho da consulta

Sobre execução de consulta SQL

No Azure Cosmos DB, os dados são armazenados em contêineres, que podem aumentar para qualquer tamanho do armazenamento ou taxa de transferência da solicitação. O Azure Cosmos DB escala perfeitamente os dados em partições físicas nos bastidores para lidar com o crescimento de dados ou aumentar a taxa de transferência fornecida. Você pode emitir consultas SQL para qualquer contêiner usando a API REST ou um com suporte SDKs do SQL.

Uma visão geral de particionamento: definir uma chave de partição como "city", que determina como os dados são divididos em partições físicas. Os dados que pertencem a uma chave de partição única (por exemplo, "city" == "Seattle") são armazenados em uma partição física e normalmente uma única partição física tem várias chaves de partição. Quando uma partição atinge seu limite de armazenamento, o serviço divide perfeitamente a partição em duas novas partições. Os dados são distribuídos uniformemente entre as novas partições, mantendo todos os dados de uma única chave de partição juntos. Como as partições são transitórias, as APIs usam uma abstração de um intervalo de chave de partição que indica os intervalos de hashes de chave de partição.

Quando você emitir uma consulta ao Azure Cosmos DB, o SDK executa essas etapas lógicas:

  • Analise a consulta SQL para determinar o plano de execução de consulta.
  • Se a consulta incluir um filtro na chave da partição, como SELECT * FROM c WHERE c.city = "Seattle", ela será roteada para uma única partição. Se a consulta não tiver um filtro na chave de partição, ela será executada em todas as partições e os resultados de cada partição serão mesclados do lado do cliente.
  • A consulta é executada dentro de cada partição em série ou em paralelo, com base na configuração do cliente. Dentro de cada partição, a consulta pode fazer uma ou mais viagens de ida e dependendo da complexidade da consulta, do tamanho da página configurada e da taxa de transferência provisionada da coleção. Cada execução retorna o número de unidades de solicitação consumidas durante a execução da consulta e as estatísticas da execução da consulta.
  • O SDK executa um resumo dos resultados da consulta em partições. Por exemplo, se a consulta envolver uma ORDER BY em partições, então os resultados de partições individuais são classificados de mesclagem para retornar os resultados em ordem classificada globalmente. Se a consulta é uma agregação como COUNT, as contagens de partições individuais são somadas para produzir a contagem total.

Os SDKs fornecem várias opções para a execução da consulta. Por exemplo, no .NET essas opções estão disponíveis na classe QueryRequestOptions. A tabela a seguir descreve essas opções e como elas afetam o tempo de execução da consulta.

Opção Descrição
EnableScanInQuery Só aplicável se a indexação para o caminho de filtro solicitado estiver desabilitada. Deve ser definido como verdadeiro se você optou por não indexar e quer executar consultas usando uma verificação completa.
MaxItemCount O número máximo de itens a serem retornados por viagem de ida e volta ao servidor. Você pode defini-lo como -1 para permitir que o servidor gerencie o número de itens a serem retornados.
MaxBufferedItemCount O número máximo de itens que podem ser armazenados em buffer no lado do cliente durante a execução de consulta paralela. Um valor da propriedade positivo limita o número de itens em buffer ao valor definido. Você pode defini-lo como menor que 0 para permitir que o sistema decida automaticamente o número de itens para buffer.
MaxConcurrency Obtém ou define o número de operações simultâneas executadas no lado do cliente durante a execução da consulta paralela. Um valor de propriedade positivo limita o número de operações simultâneas para o valor do conjunto. Você pode defini-lo como menor que 0 para permitir que o sistema decida automaticamente o número de operações simultâneas a serem executadas.
PopulateIndexMetrics Permite que a coleção de métricas de índice entenda como o mecanismo de consulta usou índices existentes e como ele poderia usar potenciais novos índices. Essa opção incorre em sobrecarga, portanto, ela só deve ser habilitada ao depurar consultas lentas.
ResponseContinuationTokenLimitInKb Você pode limitar o tamanho máximo do token de continuação retornado pelo servidor. Talvez seja necessário definir isso se o host do aplicativo tiver limites para o tamanho do cabeçalho de resposta, mas isso pode aumentar a duração geral e as RUs consumidas pela consulta.

Por exemplo, aqui está uma consulta em um contêiner particionado por /city usando o SDK do .NET:

QueryDefinition query = new QueryDefinition("SELECT * FROM c WHERE c.city = 'Seattle'");
QueryRequestOptions options = new QueryRequestOptions()
{
    MaxItemCount = -1,
    MaxBufferedItemCount = -1,
    MaxConcurrency = -1,
    PopulateIndexMetrics = true
};
FeedIterator<dynamic> feedIterator = container.GetItemQueryIterator<dynamic>(query);

FeedResponse<dynamic> feedResponse = await feedIterator.ReadNextAsync();

Cada execução de consulta corresponde a uma API REST POST com cabeçalhos definidos para as opções de solicitação de consulta e a consulta SQL no corpo. Para obter detalhes sobre as opções e os cabeçalhos de solicitação da API REST, consulte Consultar recursos usando a API REST.

Práticas recomendadas para desempenho de consulta

Os fatores a seguir geralmente têm o maior efeito sobre o desempenho da consulta do Azure Cosmos DB. Podemos obter detalhes de cada um desses fatos neste artigo.

Fator Dica
Taxa de transferência provisionada Medir RU por consulta e certificar-se de que você tem a taxa de transferência provisionada necessária para suas consultas.
Particionamento e chaves de partição Favorecer consultas com o valor de chave de partição na cláusula de filtro de baixa latência.
Opções de consulta e de SDK Siga as práticas recomendadas do SDK com conectividade direta e ajuste as opções de execução de consulta do lado do cliente.
Latência da rede Execute sempre que for possível seu aplicativo na mesma região da sua conta do Azure Cosmos DB para reduzir a latência.
Política de indexação Certifique-se de que você tem política/caminhos de indexação necessários para a consulta.
Métricas de execução da consulta Analise as métricas de execução de consulta para identificar potenciais regravações de formas de consulta e dados.

Taxa de transferência provisionada

No Azure Cosmos DB, você cria contêineres de dados, cada um com a taxa de transferência reservada expressa em RUs (unidades de solicitação) por segundo. Uma leitura de um documento de 1 KB é um RU e cada operação (incluindo consultas) é normalizada para um número fixo de RUs com base em sua complexidade. Por exemplo, se você tiver 1000 RU/s provisionado para o contêiner, e você tiver uma consulta como SELECT * FROM c WHERE c.city = 'Seattle' que consome 5 RUs, você poderá executar (1000 RU/s) / (5 RU/consulta) = 200 dessas consultas por segundo.

Se você enviar mais de 200 consultas/s (ou algumas outras operações que saturam todas as RUs provisionadas), o serviço iniciará solicitações de entrada que limitam a taxa. Os SDKs lidam automaticamente com a limitação de taxa executando uma repetição/retirada, portanto, você pode notar uma latência mais alta para essas consultas. Aumentar a taxa de transferência fornecida para o valor necessário melhora a latência da consulta e a taxa de transferência.

Para saber mais sobre unidades de solicitação, consulte Unidades de solicitação.

Particionamento e chaves de partição

Com o Azure Cosmos DB, os seguintes cenários de leitura de dados são ordenados do mais rápido/mais eficiente ao mais lento/menos eficiente.

  • GET em uma única chave de partição e ID de item, também conhecida como uma leitura de ponto
  • Consulta com uma cláusula de filtro em uma chave de partição única
  • Consulta com uma cláusula de filtro de igualdade ou intervalo em qualquer propriedade
  • Consulta sem filtros

As consultas que precisam ser executadas em todas as partições têm maior latência e podem consumir RUs mais altas. Como cada partição tem indexação automática em relação a todas as propriedades, a consulta pode ser atendida com eficiência do índice neste caso. Você pode fazer consultas que abrangem partições mais rapidamente, usando as opções de paralelismo.

Para saber mais sobre particionamento e chaves de partição, consulte Particionamento no Azure Cosmos DB.

Opções de consulta e de SDK

Confira Dicas de desempenho de consulta e Teste de desempenho para saber como obter o melhor desempenho no lado do cliente do Azure Cosmos DB usando nossas SDKs.

Latência da rede

Confira Distribuição global do Azure Cosmos DB para configurar a distribuição global e conectar-se à região mais próxima. A latência da rede tem um impacto significativo no desempenho da consulta ao precisar fazer vários processos de ida e volta ou recuperar um grande conjunto de resultados da consulta.

Você pode usar métricas de execução de consulta para recuperar o tempo de execução do servidor de consultas, permitindo diferenciar o tempo gasto na execução da consulta do tempo gasto em trânsito de rede.

Política de indexação

Confira Configurando a política de indexação para indexação de caminhos, tipos e os modos e como elas afetam a execução da consulta. Por padrão, o Azure Cosmos DB aplica a indexação automática a todos os dados e usa índices de intervalo para cadeias de caracteres e números, o que é eficaz para consultas de igualdade. Para cenários de inserção de alto desempenho, considere a exclusão de caminhos para reduzir o custo de RU para cada operação de inserção.

Você pode usar as métricas de índice para identificar quais índices são usados para cada consulta e se há índices ausentes que melhorem o desempenho da consulta.

Métricas de execução da consulta

As métricas detalhadas são retornadas para cada execução de consulta no Diagnóstico da solicitação. Essas métricas descrevem onde o tempo é gasto durante a execução da consulta e permitem a solução avançada de problemas.

Saiba mais sobre como obter as métricas de consulta.

Métrica Unidade Descrição
TotalTime milissegundos Tempo total de execução da consulta
DocumentLoadTime milliseconds Tempo gasto no carregamento de documentos
DocumentWriteTime milliseconds Tempo gasto escrevendo e serializando os documentos de saída
IndexLookupTime milissegundos Tempo gasto na camada física de índice
QueryPreparationTime milissegundos Tempo gasto na preparação da consulta
RuntimeExecutionTime milliseconds Tempo total de execução do runtime da consulta
VMExecutionTime milliseconds Tempo gasto no runtime de consulta na execução da consulta
OutputDocumentCount contagem Número de documentos de saída no conjunto de resultados
OutputDocumentSize contagem Tamanho total de documentos gerados em bytes
RetrievedDocumentCount contagem Número total de documentos recuperados
RetrievedDocumentSize bytes Tamanho total dos documentos recuperados em bytes
IndexHitRatio taxa [0,1] Taxa do número de documentos para correspondência com o filtro para o número de documentos carregados

Os SDKs do cliente podem fazer internamente várias solicitações de consulta para atender à consulta em cada partição. O cliente faz mais de uma chamada por partição se os resultados totais excederem a opção de solicitação de contagem máxima de itens, se a consulta exceder a taxa de transferência provisionada para a partição, se o conteúdo da consulta atingir o tamanho máximo por página ou se a consulta atingir o limite de tempo limite alocado pelo sistema. Cada execução de consulta parcial retorna métricas de consulta para essa página.

Aqui estão alguns exemplos de consultas e como interpretar algumas das métricas retornadas da execução da consulta:

Consulta Métrica de exemplo Descrição
SELECT TOP 100 * FROM c "RetrievedDocumentCount": 101 O número de documentos recuperados é 100 +1 para coincidir com a cláusula TOP. O tempo de consulta é gasto principalmente em WriteOutputTime e DocumentLoadTime, já que se trata de uma verificação.
SELECT TOP 500 * FROM c "RetrievedDocumentCount": 501 RetrievedDocumentCount agora é mais alto (500+1 para coincidir com a cláusula TOP).
SELECT * FROM c WHERE c.N = 55 "IndexLookupTime": "00:00:00.0009500" Cerca de 0,9 ms é gasto na IndexLookupTime para uma pesquisa de chave, porque ele é um índice de pesquisa /N/?.
SELECT * FROM c WHERE c.N > 55 "IndexLookupTime": "00:00:00.0017700" Um pouco mais de tempo (ms 1.7) é gasto em IndexLookupTime por um exame de intervalo, porque ele é um índice de pesquisa /N/?.
SELECT TOP 500 c.N FROM c "IndexLookupTime": "00:00:00.0017700" Mesmo tempo gasto em DocumentLoadTime como consultas anteriores, mas inferior DocumentWriteTime porque estamos projetando apenas uma propriedade.
SELECT TOP 500 udf.toPercent(c.N) FROM c "RuntimeExecutionTime": "00:00:00.2136500" Cerca de 213 ms é gasto na RuntimeExecutionTime executando o UDF em cada valor de c.N.
SELECT TOP 500 c.Name FROM c WHERE STARTSWITH(c.Name, 'Den') "IndexLookupTime": "00:00:00.0006400", "RuntimeExecutionTime": "00:00:00.0074100" Cerca de 0,6 ms é gasto na IndexLookupTime em /Name/?. A maioria do tempo de execução de consulta (~ 7 ms) em RuntimeExecutionTime.
SELECT TOP 500 c.Name FROM c WHERE STARTSWITH(LOWER(c.Name), 'den') "IndexLookupTime": "00:00:00", "RetrievedDocumentCount": 2491, "OutputDocumentCount": 500 A consulta é executada como uma verificação, pois ela usa LOWER, e 500 de 2491 documentos recuperados são retornados.

Próximas etapas