Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O Azure Cosmos DB é um banco de dados distribuído, rápido e flexível que pode ser dimensionado perfeitamente com garantia de níveis de latência e taxa de transferência. Você não precisa fazer grandes alterações de arquitetura nem escrever códigos complexos para dimensionar seu banco de dados com o Azure Cosmos DB. Aumentar e diminuir a escala é tão fácil quanto fazer uma única chamada de API. Para saber mais, veja Configurar o desempenho do contêiner ou Configurar o desempenho do banco de dados.
Reduzir chamadas de plano de consulta
Para executar uma consulta, um plano de consulta precisa ser criado. Solicitações de rede para o Gateway do Azure Cosmos DB adicionam à latência da operação de consulta. Há duas maneiras de remover essa solicitação e reduzir a latência da operação de consulta:
Otimizar consultas de partição única com execução direta otimista
O NoSQL do Azure Cosmos DB tem uma otimização chamada ODE (Execução Direta Otimista), que pode melhorar a eficiência de determinadas consultas NoSQL. Especificamente, as consultas que não exigem distribuição incluem aquelas que podem ser executadas em uma única partição física ou que têm respostas que não exigem paginação. Consultas que não exigem distribuição podem desprezar com segurança alguns processos, como a geração de plano de consulta do lado do cliente e a reescrita de consulta, o que reduz a latência de consulta e o custo de Request Units (RUs). Se você especificar a chave de partição na solicitação ou consulta em si (ou tiver apenas uma partição física) e os resultados da consulta não exigirem paginação, o ODE poderá melhorar suas consultas.
Observação
O ODE, que oferece melhor desempenho para consultas que não exigem distribuição, não deve ser confundido com o modo direto, que é um caminho para conectar seu aplicativo a réplicas de back-end.
A ODE já está disponível na versão 3.38.0 e posterior do SDK do .NET. Quando você executa uma consulta e especifica uma chave de partição na solicitação ou consulta em si, ou seu banco de dados tem apenas uma partição física, a execução da consulta pode usar os benefícios do ODE. Para habilitar o ODE, defina EnableOptimisticDirectExecution como true nas QueryRequestOptions.
Consultas de partição única que apresentam funções GROUP BY, ORDER BY, DISTINCT e agregação (como soma, média, min e max) podem se beneficiar significativamente do uso do ODE. No entanto, em cenários em que a consulta tem como destino várias partições ou ainda requer paginação, a latência da resposta da consulta e do custo de RU pode ser maior do que sem usar o ODE. Portanto, ao usar o ODE, você deve:
- Especifique a chave de partição na chamada ou na própria consulta.
- Verifique se o tamanho dos dados não cresceu e fez com que a partição se dividisse.
- Verifique se os resultados da consulta não exigem paginação para obter o benefício completo do ODE.
Aqui estão alguns exemplos de consultas simples de partição única que podem se beneficiar do ODE:
- SELECT * FROM r
- SELECT * FROM r WHERE r.pk == "value"
- SELECT * FROM r WHERE r.id > 5
- SELECT r.id FROM r JOIN id IN r.id
- SELECT TOP 5 r.id FROM r ORDER BY r.id
- SELECT * FROM r WHERE r.id > 5 OFFSET 5 LIMIT 3
Pode haver casos em que consultas de partição única ainda poderão exigir distribuição se o número de itens de dados aumentar ao longo do tempo e seu banco de dados do Azure Cosmos DB dividir a partição. Exemplos de consultas em que isso pode ocorrer incluem:
- SELECT Count(r.id) AS count_a FROM r
- SELECT DISTINCT r.id FROM r
- SELECT Max(r.a) as min_a FROM r
- SELECT Avg(r.a) as min_a FROM r
- SELECT Sum(r.a) as sum_a FROM r WHERE r.a > 0
Algumas consultas complexas sempre podem exigir distribuição, mesmo se forem direcionadas a uma única partição. Exemplos dessas consultas incluem:
- SELECT Sum(id) as sum_id FROM r JOIN id IN r.id
- SELECT DISTINCT r.id FROM r GROUP BY r.id
- SELECT DISTINCT r.id, Sum(r.id) as sum_a FROM r GROUP BY r.id
- SELECT Count(1) FROM (SELECT DISTINCT r.id FROM root r)
- SELECT Avg(1) AS avg FROM root r
É importante observar que o ODE pode não recuperar sempre o plano de consulta e, como resultado, não consegue impedir ou desativar consultas não suportadas. Por exemplo, após a divisão da partição, essas consultas não são mais qualificadas para ODE e, portanto, não serão executadas porque a avaliação do plano de consulta do lado do cliente as bloqueia. Para garantir a compatibilidade/continuidade do serviço, é essencial garantir que apenas as consultas que têm suporte total em cenários sem ODE (ou seja, elas executem e produzam o resultado correto no caso geral de várias partições) sejam usadas com o ODE.
Observação
O uso do ODE pode potencialmente fazer com que um novo tipo de token de continuação seja gerado. Esse token não é reconhecido pelos SDKs mais antigos por design e isso pode resultar em uma exceção de token de continuação malformada. Se você tiver um cenário em que os tokens gerados dos SDKs mais recentes sejam usados por um SDK mais antigo, recomendamos uma abordagem de duas etapas para atualizar:
- Atualize para o novo SDK e desabilite o ODE, ambos juntos como parte de uma única implantação. Aguarde até que todos os nós sejam atualizados.
- Para desabilitar o ODE, defina
EnableOptimisticDirectExecutioncomo false nas QueryRequestOptions. - Habilite o ODE como parte da segunda implantação para todos os nós.
Usar geração local de plano de consulta
O SDK do SQL inclui um ServiceInterop.dll nativo para analisar e otimizar consultas localmente. ServiceInterop.dll tem suporte apenas na plataforma Windows x64 . Os tipos de aplicativos a seguir usam o processamento de host de 32 bits por padrão. Para alterar o processamento do host para o processamento de 64 bits, siga estas etapas, com base no tipo de seu aplicativo:
Para aplicativos executáveis, você pode alterar o processamento do host definindo o destino da plataforma como x64 janela Propriedades do Projeto na guia Build.
Para projetos de teste baseados em VSTest, você pode alterar o processamento do host selecionando Teste>Configurações de Teste>Arquitetura Padrão do Processador X64 no menu de Teste do Visual Studio.
Para aplicativos Web ASP.NET implantados localmente, você pode alterar o processamento do host selecionando Usar a versão de 64 bits do IIS Express para sites e projetos em Ferramentas>Opções>Projetos e soluções>Projetos da Web.
Para aplicativos Web ASP.NET implantados no Azure, você pode alterar o processamento do host selecionando a plataforma de 64 bits em Configurações de aplicativo no portal do Azure.
Observação
Por padrão, novos projetos do Visual Studio são definidos para Qualquer CPU. Recomenda-se definir o projeto como x64 para que ele não mude para x86. Um projeto definido como Qualquer CPU pode mudar facilmente para x86 quando uma dependência somente x86 é adicionada.
ServiceInterop.dll precisa estar na pasta da qual a DLL do SDK está sendo executada. Isso é importante apenas quando você copia DLLs manualmente ou tem sistemas personalizados de compilação/implantação.
Usar consultas de partição única
Para consultas que direcionam uma chave de partição ao definir a propriedade PartitionKeyQueryRequestOptions e não contêm agregações (incluindo Distinct, DCount ou Group By). Neste exemplo, o campo de chave de partição de /state é filtrado no valor Washington.
using (FeedIterator<MyItem> feedIterator = container.GetItemQueryIterator<MyItem>(
"SELECT * FROM c WHERE c.city = 'Seattle' AND c.state = 'Washington'"
{
// ...
}
Opcionalmente, você pode fornecer a chave de partição como parte do objeto de opções de solicitação.
using (FeedIterator<MyItem> feedIterator = container.GetItemQueryIterator<MyItem>(
"SELECT * FROM c WHERE c.city = 'Seattle'",
requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Washington")}))
{
// ...
}
Importante
Em clientes que executam um sistema operacional não Windows, como Linux e macOS, a chave de partição sempre deve ser especificada no objeto de opções de solicitação.
Observação
Consultas entre partições exigem que o SDK visite todas as partições existentes para verificar se há resultados. Quanto mais partições físicas o contêiner tiver, mais lentas elas poderão ficar.
Evitar recriar o iterador desnecessariamente
Quando todos os resultados da consulta forem consumidos pelo componente atual, não é necessário criar novamente o iterador com a continuação para cada página. Sempre prefira esvaziar totalmente a consulta, a menos que a paginação seja controlada por outro componente de chamada:
using (FeedIterator<MyItem> feedIterator = container.GetItemQueryIterator<MyItem>(
"SELECT * FROM c WHERE c.city = 'Seattle'",
requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Washington")}))
{
while (feedIterator.HasMoreResults)
{
foreach(MyItem document in await feedIterator.ReadNextAsync())
{
// Iterate through documents
}
}
}
Ajustar o grau de paralelismo
Em consultas, ajuste a propriedade MaxConcurrencyQueryRequestOptions para identificar as melhores configurações para seu aplicativo, especialmente se você executar consultas entre partições (sem um filtro no valor da chave de partição).
MaxConcurrency controla o número máximo de tarefas paralelas, ou seja, o número máximo de partições a serem visitadas paralelamente. Definir o valor como -1 permite que o SDK decida a simultaneidade ideal.
using (FeedIterator<MyItem> feedIterator = container.GetItemQueryIterator<MyItem>(
"SELECT * FROM c WHERE c.city = 'Seattle'",
requestOptions: new QueryRequestOptions() {
PartitionKey = new PartitionKey("Washington"),
MaxConcurrency = -1 }))
{
// ...
}
Vamos supor que:
- D = Número máximo padrão de tarefas paralelas (= número total de processadores no computador cliente)
- P = número máximo especificado pelo usuário de tarefas paralelas
- N = número de partições que precisam ser visitadas para responder a uma consulta
Veja a seguir as implicações de como as consultas paralelas se comportam para valores diferentes de P.
- (P == 0) => Modo serial
- (P == 1) => Máximo de uma tarefa
- (P > 1) => Mínimo (P, N) de tarefas paralelas
- (P < 1) => Mínimo (N, D) de tarefas paralelas
Ajustar o tamanho da página
Quando você envia uma consulta SQL, os resultados serão retornados de maneira segmentada se o conjunto de resultados for muito grande.
Observação
A propriedade MaxItemCount não deve ser usada apenas para paginação. Seu uso principal é aprimorar o desempenho das consultas reduzindo o número máximo de itens retornados em uma só página.
Você também pode definir o tamanho da página usando os SDKs do Azure Cosmos DB disponíveis. A propriedade MaxItemCount no QueryRequestOptions permite que você defina o número máximo de itens a serem retornados na operação de enumeração. Quando MaxItemCount é definido como -1, o SDK localiza automaticamente o valor ideal, dependendo do tamanho do documento. Por exemplo:
using (FeedIterator<MyItem> feedIterator = container.GetItemQueryIterator<MyItem>(
"SELECT * FROM c WHERE c.city = 'Seattle'",
requestOptions: new QueryRequestOptions() {
PartitionKey = new PartitionKey("Washington"),
MaxItemCount = 1000}))
{
// ...
}
Quando uma consulta é executada, os dados resultantes são enviados dentro de um pacote TCP. Se você especificar um valor muito baixo para MaxItemCount, o número de viagens necessárias para enviar os dados no pacote TCP será alto, o que afetará o desempenho. Portanto, se você não tiver certeza de qual valor definir para a MaxItemCount propriedade, é melhor defini-la como -1 e permitir que o SDK escolha o valor padrão.
Ajustar o tamanho do buffer
A consulta paralela foi projetada para pré-realizar resultados enquanto o lote atual de resultados está sendo processado pelo cliente. Essa pré-busca ajuda a melhorar a latência geral de uma consulta. A propriedade QueryRequestOptions limita o número de resultados pré-buscados. Defina MaxBufferedItemCount como o número esperado de resultados retornados (ou um número maior) para permitir que a consulta receba o benefício máximo da pré-busca. Se você definir esse valor como -1, o sistema determinará automaticamente o número de itens a serem armazenados em buffer.
using (FeedIterator<MyItem> feedIterator = container.GetItemQueryIterator<MyItem>(
"SELECT * FROM c WHERE c.city = 'Seattle'",
requestOptions: new QueryRequestOptions() {
PartitionKey = new PartitionKey("Washington"),
MaxBufferedItemCount = -1}))
{
// ...
}
O pré-carregamento funciona da mesma forma, independentemente do grau de paralelismo, e há um único buffer para os dados de todas as partições.
Próximas etapas
Para saber mais sobre o desempenho usando o SDK do .NET:
Reduzir chamadas de plano de consulta
Para executar uma consulta, um plano de consulta precisa ser criado. Solicitações de rede para o Gateway do Azure Cosmos DB adicionam à latência da operação de consulta.
Usar o cache do plano de consulta
O plano de consulta, para uma consulta com escopo para uma única partição, é armazenado em cache no cliente. Isso elimina a necessidade de fazer uma chamada para o gateway para recuperar o plano de consulta após a primeira chamada. A chave do plano de consulta em cache é a cadeia de caracteres da consulta SQL. Você precisa verificar se a consulta está parametrizada. Caso contrário, a pesquisa no cache do plano de consulta geralmente resulta em uma falha de cache, pois é improvável que a string de consulta seja idêntica entre as chamadas. O cache do plano de consulta é habilitado por padrão para o Java SDK versão 4.20.0 e superior e para o SDK Spring Data Azure Cosmos DB versão 3.13.0 e superior.
Usar consultas de partição única parametrizadas
Para consultas parametrizadas que têm como escopo uma chave de partição com setPartitionKeyCosmosQueryRequestOptions e não contêm agregações (incluindo Distinct, DCount ou Group By), o plano de consulta pode ser evitado:
CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
options.setPartitionKey(new PartitionKey("Washington"));
ArrayList<SqlParameter> paramList = new ArrayList<SqlParameter>();
paramList.add(new SqlParameter("@city", "Seattle"));
SqlQuerySpec querySpec = new SqlQuerySpec(
"SELECT * FROM c WHERE c.city = @city",
paramList);
// Sync API
CosmosPagedIterable<MyItem> filteredItems =
container.queryItems(querySpec, options, MyItem.class);
// Async API
CosmosPagedFlux<MyItem> filteredItems =
asyncContainer.queryItems(querySpec, options, MyItem.class);
Observação
Consultas entre partições exigem que o SDK visite todas as partições existentes para verificar se há resultados. Quanto mais partições físicas o contêiner tiver, mais lentas elas poderão ficar.
Ajustar o grau de paralelismo
As consultas paralelas funcionam consultando várias partições em paralelo. No entanto, os dados de um contêiner particionado individual são buscados em série com relação à consulta. Portanto, use setMaxDegreeOfParallelism no CosmosQueryRequestOptions para definir o valor do número de partições que você possui. Se você não souber o número de partições, poderá usar setMaxDegreeOfParallelism para definir um número alto, e o sistema escolherá o mínimo (número de partições, entrada fornecida pelo usuário) como o grau máximo de paralelismo. Definir o valor como -1 permite que o SDK decida a simultaneidade ideal.
É importante observar que consultas paralelas produzem os melhores benefícios se os dados forem distribuídos uniformemente em todas as partições em relação à consulta. Se o contêiner particionado for particionado de forma que todos ou a maioria dos dados retornados por uma consulta estejam concentrados em algumas partições (uma partição na pior das hipóteses), o desempenho da consulta será degradado.
CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
options.setPartitionKey(new PartitionKey("Washington"));
options.setMaxDegreeOfParallelism(-1);
// Define the query
// Sync API
CosmosPagedIterable<MyItem> filteredItems =
container.queryItems(querySpec, options, MyItem.class);
// Async API
CosmosPagedFlux<MyItem> filteredItems =
asyncContainer.queryItems(querySpec, options, MyItem.class);
Vamos supor que:
- D = Número máximo padrão de tarefas paralelas (= número total de processadores no computador cliente)
- P = número máximo especificado pelo usuário de tarefas paralelas
- N = número de partições que precisam ser visitadas para responder a uma consulta
Veja a seguir as implicações de como as consultas paralelas se comportam para valores diferentes de P:
- (P == 0) => Modo serial
- (P == 1) => Máximo de uma tarefa
- (P > 1) => Mínimo (P, N) de tarefas paralelas
- (P == -1) => Mín. (N, D) de tarefas paralelas
Ajustar o tamanho da página
Quando você envia uma consulta SQL, os resultados serão retornados de maneira segmentada se o conjunto de resultados for muito grande. Por padrão, os resultados são retornados em blocos de 100 itens ou 4 MB, o limite que for atingido primeiro. Aumentar o tamanho da página reduz o número de viagens de ida e volta necessárias e aumenta o desempenho para consultas que retornam mais de 100 itens. Se você não tiver certeza de qual valor definir, 1000 normalmente é uma boa opção. O consumo de memória aumenta à medida que o tamanho da página aumenta, portanto, se sua carga de trabalho for sensível à memória, considere um valor menor.
Você pode usar o parâmetro pageSize no iterableByPage() para API síncrona e byPage() para a API assíncrona, para definir um tamanho de página:
// Sync API
Iterable<FeedResponse<MyItem>> filteredItemsAsPages =
container.queryItems(querySpec, options, MyItem.class).iterableByPage(continuationToken,pageSize);
for (FeedResponse<MyItem> page : filteredItemsAsPages) {
for (MyItem item : page.getResults()) {
//...
}
}
// Async API
Flux<FeedResponse<MyItem>> filteredItemsAsPages =
asyncContainer.queryItems(querySpec, options, MyItem.class).byPage(continuationToken,pageSize);
filteredItemsAsPages.map(page -> {
for (MyItem item : page.getResults()) {
//...
}
}).subscribe();
Ajustar o tamanho do buffer
A consulta paralela foi projetada para pré-realizar resultados enquanto o lote atual de resultados está sendo processado pelo cliente. A pré-busca ajuda na melhoria geral da latência de uma consulta.
setMaxBufferedItemCountCosmosQueryRequestOptions limita o número de resultados pré-buscados. Para maximizar a pré-busca, defina como maxBufferedItemCount um número maior do que o pageSize (OBSERVAÇÃO: isso também pode resultar em alto consumo de memória). Para minimizar a pré-busca, defina o maxBufferedItemCount igual ao pageSize. Se você definir esse valor como 0, o sistema determinará automaticamente o número de itens a serem armazenados em buffer.
CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
options.setPartitionKey(new PartitionKey("Washington"));
options.setMaxBufferedItemCount(-1);
// Define the query
// Sync API
CosmosPagedIterable<MyItem> filteredItems =
container.queryItems(querySpec, options, MyItem.class);
// Async API
CosmosPagedFlux<MyItem> filteredItems =
asyncContainer.queryItems(querySpec, options, MyItem.class);
O pré-carregamento funciona da mesma forma, independentemente do grau de paralelismo, e há um único buffer para os dados de todas as partições.
Próximas etapas
Para saber mais sobre o desempenho usando o SDK do Java:
Reduzir chamadas de plano de consulta
Para executar uma consulta, um plano de consulta precisa ser criado. Solicitações de rede para o Gateway do Azure Cosmos DB adicionam à latência da operação de consulta. Há uma maneira de remover essa solicitação e reduzir a latência da operação de consulta de partição única. Para consultas de partição única, especifique o valor da chave de partição para o item e passe-o como partition_key argumento:
items = container.query_items(
query="SELECT * FROM r where r.city = 'Seattle'",
partition_key="Washington"
)
Ajustar o tamanho da página
Quando você envia uma consulta SQL, os resultados serão retornados de maneira segmentada se o conjunto de resultados for muito grande. A propriedade max_item_count permite que você defina o número máximo de itens a serem retornados na operação de enumeração.
items = container.query_items(
query="SELECT * FROM r where r.city = 'Seattle'",
partition_key="Washington",
max_item_count=1000
)
Próximas etapas
Para saber mais sobre como usar o SDK do Python para API para NoSQL:
Reduzir chamadas de plano de consulta
Para executar uma consulta, um plano de consulta precisa ser criado. Solicitações de rede para o Gateway do Azure Cosmos DB adicionam à latência da operação de consulta. Há uma maneira de remover essa solicitação e reduzir a latência da operação de consulta de partição única. Para consultas de partição única, o escopo de uma consulta para uma única partição pode ser feito de duas maneiras.
Usando uma expressão de consulta parametrizada e especificando a chave de partição na instrução de consulta. A consulta é composta programaticamente para SELECT * FROM todo t WHERE t.partitionKey = 'Bikes, Touring Bikes':
// find all items with same categoryId (partitionKey)
const querySpec = {
query: "select * from products p where p.categoryId=@categoryId",
parameters: [
{
name: "@categoryId",
value: "Bikes, Touring Bikes"
}
]
};
// Get items
const { resources } = await container.items.query(querySpec).fetchAll();
for (const item of resources) {
console.log(`${item.id}: ${item.name}, ${item.sku}`);
}
Ou especifique partitionKey em FeedOptions e passe-o como argumento:
const querySpec = {
query: "select * from products p"
};
const { resources } = await container.items.query(querySpec, { partitionKey: "Bikes, Touring Bikes" }).fetchAll();
for (const item of resources) {
console.log(`${item.id}: ${item.name}, ${item.sku}`);
}
Ajustar o tamanho da página
Quando você envia uma consulta SQL, os resultados serão retornados de maneira segmentada se o conjunto de resultados for muito grande. A propriedade MaxItemCount no permite que você defina o número máximo de itens a serem retornados na operação de enumeração.
const querySpec = {
query: "select * from products p where p.categoryId=@categoryId",
parameters: [
{
name: "@categoryId",
value: items[2].categoryId
}
]
};
const { resources } = await container.items.query(querySpec, { maxItemCount: 1000 }).fetchAll();
for (const item of resources) {
console.log(`${item.id}: ${item.name}, ${item.sku}`);
}
Controle de consulta aprimorado
Para a versão 4.3.0 e posteriores do SDK do JS do Cosmos DB, o sinalizador enableQueryControl foi introduzido, o que fornece maior controle sobre a execução da consulta, oferecendo mais flexibilidade no gerenciamento do consumo de RUs (Unidades de Requisição).
Por padrão, enableQueryControl é definido como false e o SDK garante que cada chamada fetchNext retornaria maxItemCount resultados, desde que essa quantidade de resultados existisse no back-end. Mas para atender à contagem de resultados garantida, o SDK pode consultar partições de back-end várias vezes em uma única fetchNext iteração. Às vezes, isso pode resultar em uma latência imprevisível e no esgotamento de RUs sem controle de usuário, especialmente quando os resultados são distribuídos entre partições.
Quando enableQueryControl é definido como true, cada chamada fetchNext agora consulta até maxDegreeOfParallelism partições físicas. Se nenhum resultado for encontrado ou os resultados ainda não estiverem prontos para serem atendidos, o SDK retornará páginas vazias em vez de continuar pesquisando todas as partições em segundo plano. Dessa forma, os usuários ganham um controle mais fino sobre a execução da consulta com latência previsível e dados de consumo de RU granulares.
const options = {
enableQueryControl: true, // Flag to enable new query pipeline.
maxItemCount: 100,
maxDegreeOfParallelism: 6
};
const querySpec = {
query: "select * from products p where p.categoryId=@categoryId",
parameters: [
{
name: "@categoryId",
value: items[2].categoryId
}
]
};
const queryIterator = container.items.query(querySpec, options);
// use this iterator to fetch results.
Próximas etapas
Para saber mais sobre como usar o SDK do Node.js para API para NoSQL: