Otimizar as consultas de pesquisa no Azure Monitor

O Azure Monitor Logs usa o Azure Data Explorer para armazenar dados de log e executar consultas para analisar esses dados. Ele cria, gerencia e mantém os clusters do Azure Data Explorer para você e os otimiza para sua carga de trabalho de análise de log. Quando você executa uma consulta, ela é otimizada e roteada para o cluster apropriado do Azure Data Explorer que armazena os dados do espaço de trabalho.

Os Logs do Azure Monitor e o Azure Data Explorer usam muitos mecanismos automáticos de otimização de consulta. As otimizações automáticas fornecem um impulso significativo, mas há alguns casos em que você pode melhorar drasticamente o desempenho da sua consulta. Este artigo explica as considerações de desempenho e várias técnicas para corrigi-las.

A maioria das técnicas é comum a consultas que são executadas diretamente no Azure Data Explorer e Azure Monitor Logs. Várias considerações exclusivas dos Logs do Azure Monitor também são discutidas. Para obter mais dicas de otimização do Azure Data Explorer, consulte Práticas recomendadas de consulta.

As consultas otimizadas irão:

  • Execute mais rapidamente e reduza a duração total da execução da consulta.
  • Têm menor chance de serem estrangulados ou rejeitados.

Preste especial atenção às consultas usadas para uso recorrente e simultâneo, como painéis, alertas, Aplicativos Lógicos do Azure e Power BI. O impacto de uma consulta ineficaz nestes casos é substancial.

Aqui está um passo a passo detalhado em vídeo sobre como otimizar consultas.

Painel Detalhes da Consulta

Depois de executar uma consulta no Log Analytics, selecione Detalhes da consulta no canto inferior direito da tela para abrir o painel Detalhes da consulta . Este painel mostra os resultados de vários indicadores de desempenho para a consulta. Estes indicadores de desempenho são descritos na secção seguinte.

Screenshot that shows the Query Details pane in Azure Monitor Log Analytics.

Indicadores de desempenho da consulta

Os seguintes indicadores de desempenho de consulta estão disponíveis para cada consulta executada:

Total CPU

A CPU de computação real que foi investida para processar essa consulta em todos os nós de processamento de consulta. Como a maioria das consultas é executada em um grande número de nós, esse total geralmente será muito maior do que a duração que a consulta levou para ser executada.

Uma consulta que usa mais de 100 segundos de CPU é considerada uma consulta que consome recursos excessivos. Uma consulta que usa mais de 1.000 segundos de CPU é considerada uma consulta abusiva e pode ser limitada.

O tempo de processamento de consultas é gasto em:

  • Recuperação de dados: a recuperação de dados antigos consumirá mais tempo do que a recuperação de dados recentes.
  • Tratamento de dados: Lógica e avaliação dos dados.

Além do tempo gasto nos nós de processamento de consulta, o Azure Monitor Logs gasta tempo em:

  • Autenticar o usuário e verificar se ele tem permissão para acessar esses dados.
  • Localizar o armazenamento de dados.
  • Analisar a consulta.
  • Alocando os nós de processamento de consulta.

Esse tempo não está incluído no tempo total da CPU da consulta.

Filtragem antecipada de registros antes de usar funções de alta CPU

Alguns dos comandos e funções de consulta são pesados em seu consumo de CPU. Este caso é especialmente verdadeiro para comandos que analisam JSON e XML ou extraem expressões regulares complexas. Essa análise pode acontecer explicitamente através das funções parse_json() ou parse_xml() ou implicitamente quando se refere a colunas dinâmicas.

Essas funções consomem CPU proporcionalmente ao número de linhas que estão processando. A otimização mais eficiente é adicionar where condições no início da consulta. Dessa forma, eles podem filtrar o maior número possível de registros antes que a função com uso intensivo de CPU seja executada.

Por exemplo, as consultas a seguir produzem exatamente o mesmo resultado. Mas o segundo é o mais eficiente porque a condição where antes de analisar exclui muitos registros:

//less efficient
SecurityEvent
| extend Details = parse_xml(EventData)
| extend FilePath = tostring(Details.UserData.RuleAndFileData.FilePath)
| extend FileHash = tostring(Details.UserData.RuleAndFileData.FileHash)
| where FileHash != "" and FilePath !startswith "%SYSTEM32"  // Problem: irrelevant results are filtered after all processing and parsing is done
| summarize count() by FileHash, FilePath
//more efficient
SecurityEvent
| where EventID == 8002 //Only this event have FileHash
| where EventData !has "%SYSTEM32" //Early removal of unwanted records
| extend Details = parse_xml(EventData)
| extend FilePath = tostring(Details.UserData.RuleAndFileData.FilePath)
| extend FileHash = tostring(Details.UserData.RuleAndFileData.FileHash)
| where FileHash != "" and FilePath !startswith "%SYSTEM32"  // exact removal of results. Early filter is not accurate enough
| summarize count() by FileHash, FilePath
| where FileHash != "" // No need to filter out %SYSTEM32 here as it was removed before

Evite usar cláusulas avaliadas onde

As consultas que contêm cláusulas where em uma coluna avaliada em vez de em colunas que estão fisicamente presentes no conjunto de dados perdem eficiência. A filtragem em colunas avaliadas impede algumas otimizações do sistema quando grandes conjuntos de dados são manipulados.

Por exemplo, as consultas a seguir produzem exatamente o mesmo resultado. Mas o segundo é mais eficiente porque a condição where refere-se a uma coluna embutida:

//less efficient
Syslog
| extend Msg = strcat("Syslog: ",SyslogMessage)
| where  Msg  has "Error"
| count 
//more efficient
Syslog
| where  SyslogMessage  has "Error"
| count 

Em alguns casos, a coluna avaliada é criada implicitamente pelo mecanismo de processamento de consultas porque a filtragem não é feita apenas no campo:

//less efficient
SecurityEvent
| where tolower(Process) == "conhost.exe"
| count 
//more efficient
SecurityEvent
| where Process =~ "conhost.exe"
| count 

Use comandos e dimensões de agregação eficazes em resumir e unir

Alguns comandos de agregação como max(), sum(), count() e avg() têm baixo impacto na CPU devido à sua lógica. Outros comandos são mais complexos e incluem heurísticas e estimativas que permitem que sejam executados de forma eficiente. Por exemplo, dcount() usa o algoritmo HyperLogLog para fornecer uma estimativa próxima a uma contagem distinta de grandes conjuntos de dados sem realmente contar cada valor.

As funções de percentil estão fazendo aproximações semelhantes usando o algoritmo de percentil de classificação mais próximo. Vários dos comandos incluem parâmetros opcionais para reduzir o seu impacto. Por exemplo, a função makeset() tem um parâmetro opcional para definir o tamanho máximo do conjunto, o que afeta significativamente a CPU e a memória.

Os comandos de junção e resumo podem causar alta utilização da CPU quando eles estão processando um grande conjunto de dados. Sua complexidade está diretamente relacionada ao número de valores possíveis, referidos como cardinalidade, das colunas que são usadas como o by in summarize ou como os join atributos. Para obter explicações e otimização de e , consulte seus artigos de documentação e summarizedicas de join otimização.

Por exemplo, as consultas a seguir produzem exatamente o mesmo resultado porque CounterPath é sempre um para um mapeado para CounterName e ObjectName. A segunda é mais eficiente porque a dimensão de agregação é menor:

//less efficient
Perf
| summarize avg(CounterValue) 
by CounterName, CounterPath, ObjectName
//make the group expression more compact improve the performance
Perf
| summarize avg(CounterValue), any(CounterName), any(ObjectName) 
by CounterPath

O consumo da CPU também pode ser afetado por where condições ou colunas estendidas que exigem computação intensiva. Todas as comparações triviais de cadeia de caracteres, como igual == e startswith, têm aproximadamente o mesmo impacto na CPU. As correspondências avançadas de texto têm mais impacto. Especificamente, o operador has é mais eficiente do que o operador contém. Devido às técnicas de manipulação de cadeias de caracteres, é mais eficiente procurar cadeias de caracteres com mais de quatro caracteres do que cadeias curtas.

Por exemplo, as consultas a seguir produzem resultados semelhantes, dependendo da Computer política de nomenclatura. Mas o segundo é mais eficiente:

//less efficient – due to filter based on contains
Heartbeat
| where Computer contains "Production" 
| summarize count() by ComputerIP 
//less efficient – due to filter based on extend
Heartbeat
| extend MyComputer = Computer
| where MyComputer startswith "Production" 
| summarize count() by ComputerIP 
//more efficient
Heartbeat
| where Computer startswith "Production" 
| summarize count() by ComputerIP 

Nota

Este indicador apresenta apenas a CPU do cluster imediato. Em uma consulta multirregião, ele representaria apenas uma das regiões. Em uma consulta com vários espaços de trabalho, ele pode não incluir todos os espaços de trabalho.

Evite a análise completa de XML e JSON quando a análise de cadeia de caracteres funciona

A análise completa de um objeto XML ou JSON pode consumir altos recursos de CPU e memória. Em muitos casos, quando apenas um ou dois parâmetros são necessários e os objetos XML ou JSON são simples, é mais fácil analisá-los como cadeias de caracteres. Use o operador de análise ou outras técnicas de análise de texto. O aumento de desempenho será mais significativo porque o número de registros no objeto XML ou JSON aumenta. É essencial quando o número de registos atinge dezenas de milhões.

Por exemplo, a consulta a seguir retorna exatamente os mesmos resultados que as consultas anteriores sem executar a análise XML completa. A consulta faz algumas suposições sobre a estrutura do arquivo XML, como o FilePath elemento vem depois FileHash e nenhum deles tem atributos:

//even more efficient
SecurityEvent
| where EventID == 8002 //Only this event have FileHash
| where EventData !has "%SYSTEM32" //Early removal of unwanted records
| parse EventData with * "<FilePath>" FilePath "</FilePath>" * "<FileHash>" FileHash "</FileHash>" *
| summarize count() by FileHash, FilePath
| where FileHash != "" // No need to filter out %SYSTEM32 here as it was removed before

Dados utilizados para consulta processada

Um fator crítico no processamento da consulta é o volume de dados que é digitalizado e usado para o processamento da consulta. O Azure Data Explorer usa otimizações agressivas que reduzem drasticamente o volume de dados em comparação com outras plataformas de dados. Ainda assim, há fatores críticos na consulta que podem afetar o volume de dados usado.

Uma consulta que processa mais de 2.000 KB de dados é considerada uma consulta que consome recursos excessivos. Uma consulta que processa mais de 20.000 KB de dados é considerada uma consulta abusiva e pode ser limitada.

Nos Logs do Azure Monitor, a TimeGenerated coluna é usada como uma maneira de indexar os dados. Restringir os valores a um intervalo o mais estreito possível melhorará o desempenho da TimeGenerated consulta. O intervalo estreito limita significativamente a quantidade de dados que devem ser processados.

Evitar a utilização desnecessária de operadores de pesquisa e da união

Outro fator que aumenta os dados processados é o uso de um grande número de tabelas. Esse cenário geralmente acontece quando search * comandos e union * são usados. Esses comandos forçam o sistema a avaliar e verificar dados de todas as tabelas no espaço de trabalho. Em alguns casos, pode haver centenas de tabelas no espaço de trabalho. Tente evitar o uso search * ou qualquer pesquisa sem delimitá-la a uma tabela específica.

Por exemplo, as seguintes consultas produzem exatamente o mesmo resultado, mas a última é a mais eficiente:

// This version scans all tables though only Perf has this kind of data
search "Processor Time" 
| summarize count(), avg(CounterValue)  by Computer
// This version scans all strings in Perf tables – much more efficient
Perf
| search "Processor Time" 
| summarize count(), avg(CounterValue)  by Computer
// This is the most efficient version 
Perf 
| where CounterName == "% Processor Time"  
| summarize count(), avg(CounterValue)  by Computer

Adicionar filtros antecipados à consulta

Outro método para reduzir o volume de dados é ter onde as condições no início da consulta. A plataforma Azure Data Explorer inclui um cache que permite saber quais partições incluem dados relevantes para uma condição específica where . Por exemplo, se uma consulta contiver where EventID == 4624, ela distribuirá a consulta somente para nós que manipulam partições com eventos correspondentes.

As consultas de exemplo a seguir produzem exatamente o mesmo resultado, mas a segunda é mais eficiente:

//less efficient
SecurityEvent
| summarize LoginSessions = dcount(LogonGuid) by Account
//more efficient
SecurityEvent
| where EventID == 4624 //Logon GUID is relevant only for logon event
| summarize LoginSessions = dcount(LogonGuid) by Account

Evite várias verificações dos mesmos dados de origem usando funções de agregação condicional e a função materialize

Quando uma consulta tem várias subconsultas que são mescladas usando operadores de junção ou união, cada subconsulta verifica toda a fonte separadamente. Em seguida, mescla os resultados. Essa ação multiplica o número de vezes que os dados são verificados, o que é um fator crítico em grandes conjuntos de dados.

Uma técnica para evitar esse cenário é usando as funções de agregação condicional. A maioria das funções de agregação usadas em um operador de resumo tem uma versão condicionada que você pode usar para um único operador de resumo com várias condições.

Por exemplo, as consultas a seguir mostram o número de eventos de login e o número de eventos de execução de processo para cada conta. Eles retornam os mesmos resultados, mas a primeira consulta verifica os dados duas vezes. A segunda consulta verifica apenas uma vez:

//Scans the SecurityEvent table twice and perform expensive join
SecurityEvent
| where EventID == 4624 //Login event
| summarize LoginCount = count() by Account
| join 
(
    SecurityEvent
    | where EventID == 4688 //Process execution event
    | summarize ExecutionCount = count(), ExecutedProcesses = make_set(Process) by Account
) on Account
//Scan only once with no join
SecurityEvent
| where EventID == 4624 or EventID == 4688 //early filter
| summarize LoginCount = countif(EventID == 4624), ExecutionCount = countif(EventID == 4688), ExecutedProcesses = make_set_if(Process,EventID == 4688)  by Account

Outro caso em que as subconsultas são desnecessárias é a pré-filtragem para um operador de análise para garantir que ele processe apenas registros que correspondam a um padrão específico. Eles são desnecessários porque o operador de análise e outros operadores semelhantes retornam resultados vazios quando o padrão não corresponde. As duas consultas a seguir retornam exatamente os mesmos resultados, mas a segunda consulta verifica os dados apenas uma vez. Na segunda consulta, cada comando de análise é relevante apenas para seus eventos. O extend operador mostra depois como se referir a uma situação de dados vazios:

//Scan SecurityEvent table twice
union(
SecurityEvent
| where EventID == 8002 
| parse EventData with * "<FilePath>" FilePath "</FilePath>" * "<FileHash>" FileHash "</FileHash>" *
| distinct FilePath
),(
SecurityEvent
| where EventID == 4799
| parse EventData with * "CallerProcessName\">" CallerProcessName1 "</Data>" * 
| distinct CallerProcessName1
)
//Single scan of the SecurityEvent table
SecurityEvent
| where EventID == 8002 or EventID == 4799
| parse EventData with * "<FilePath>" FilePath "</FilePath>" * "<FileHash>" FileHash "</FileHash>" * //Relevant only for event 8002
| parse EventData with * "CallerProcessName\">" CallerProcessName1 "</Data>" *  //Relevant only for event 4799
| extend FilePath = iif(isempty(CallerProcessName1),FilePath,"")
| distinct FilePath, CallerProcessName1

Quando a consulta anterior não permite que você evite o uso de subconsultas, outra técnica é sugerir ao mecanismo de consulta que há uma única fonte de dados usada em cada uma delas usando a função materialize(). Essa técnica é útil quando os dados de origem são provenientes de uma função usada várias vezes na consulta. Materialize é eficaz quando a saída da subconsulta é muito menor do que a entrada. O mecanismo de consulta armazenará em cache e reutilizará a saída em todas as ocorrências.

Reduzir o número de colunas recuperadas

Como o Azure Data Explorer é um armazenamento de dados colunar, a recuperação de cada coluna é independente das outras. O número de colunas recuperadas influencia diretamente o volume geral de dados. Você só deve incluir as colunas na saída que são necessárias, resumindo os resultados ou projetando as colunas específicas.

O Azure Data Explorer tem várias otimizações para reduzir o número de colunas recuperadas. Se ele determinar que uma coluna não é necessária, por exemplo, se ela não for referenciada no comando summarize , ela não a recuperará.

Por exemplo, a segunda consulta pode processar três vezes mais dados porque precisa buscar não uma coluna, mas três:

//Less columns --> Less data
SecurityEvent
| summarize count() by Computer  
//More columns --> More data
SecurityEvent
| summarize count(), dcount(EventID), avg(Level) by Computer  

Período de tempo da consulta processada

Todos os logs nos Logs do Azure Monitor são particionados de acordo com a TimeGenerated coluna. O número de partições que são acessadas estão diretamente relacionadas ao período de tempo. Reduzir o intervalo de tempo é a maneira mais eficiente de garantir uma execução de consulta rápida.

Uma consulta com um período de tempo superior a 15 dias é considerada uma consulta que consome recursos excessivos. Uma consulta com um período de tempo superior a 90 dias é considerada uma consulta abusiva e pode ser limitada.

Você pode definir o intervalo de tempo usando o seletor de intervalo de tempo na tela do Log Analytics, conforme descrito em Escopo e intervalo de tempo da consulta de log no Azure Monitor Log Analytics. Esse método é recomendado porque o intervalo de tempo selecionado é passado para o back-end usando os metadados de consulta.

Um método alternativo é incluir explicitamente uma condição where na TimeGenerated consulta. Use esse método porque ele garante que o período de tempo seja fixo, mesmo quando a consulta é usada a partir de uma interface diferente.

Certifique-se de que todas as partes da consulta têm TimeGenerated filtros. Quando uma consulta tem subconsultas buscando dados de várias tabelas ou da mesma tabela, cada consulta deve incluir sua própria condição where .

Verifique se todas as subconsultas têm o filtro TimeGenerated

Por exemplo, na consulta a seguir, a Perf tabela será verificada apenas para o último dia. A Heartbeat tabela será digitalizada para todo o seu histórico, que pode ser de até dois anos:

Perf
| where TimeGenerated > ago(1d)
| summarize avg(CounterValue) by Computer, CounterName
| join kind=leftouter (
    Heartbeat
    //No time span filter in this part of the query
    | summarize IPs = makeset(ComputerIP, 10) by  Computer
) on Computer

Um caso comum em que tal erro ocorre é quando arg_max() é usado para encontrar a ocorrência mais recente. Por exemplo:

Perf
| where TimeGenerated > ago(1d)
| summarize avg(CounterValue) by Computer, CounterName
| join kind=leftouter (
    Heartbeat
    //No time span filter in this part of the query
    | summarize arg_max(TimeGenerated, *), min(TimeGenerated)   
by Computer
) on Computer

Você pode corrigir facilmente essa situação adicionando um filtro de tempo na consulta interna:

Perf
| where TimeGenerated > ago(1d)
| summarize avg(CounterValue) by Computer, CounterName
| join kind=leftouter (
    Heartbeat
    | where TimeGenerated > ago(1d) //filter for this part
    | summarize arg_max(TimeGenerated, *), min(TimeGenerated)   
by Computer
) on Computer

Outro exemplo dessa falha é quando você executa a filtragem de escopo de tempo logo após uma união em várias tabelas. Quando você executa a união, cada subconsulta deve ter escopo. Você pode usar uma instrução let para garantir a consistência do escopo.

Por exemplo, a consulta a seguir verificará todos os dados nas Heartbeat tabelas e Perf e não apenas no último dia:

Heartbeat 
| summarize arg_min(TimeGenerated,*) by Computer
| union (
    Perf 
    | summarize arg_min(TimeGenerated,*) by Computer) 
| where TimeGenerated > ago(1d)
| summarize min(TimeGenerated) by Computer

Para corrigir a consulta:

let MinTime = ago(1d);
Heartbeat 
| where TimeGenerated > MinTime
| summarize arg_min(TimeGenerated,*) by Computer
| union (
    Perf 
    | where TimeGenerated > MinTime
    | summarize arg_min(TimeGenerated,*) by Computer) 
| summarize min(TimeGenerated) by Computer

Limitações de medição de tempo

A medição é sempre maior do que o tempo real especificado. Por exemplo, se o filtro na consulta for de 7 dias, o sistema poderá verificar 7,5 ou 8,1 dias. Essa variação ocorre porque o sistema está particionando os dados em partes de tamanhos variáveis. Para garantir que todos os registros relevantes sejam verificados, o sistema verifica toda a partição. Este processo pode abranger várias horas e até mais do que um dia.

Há vários casos em que o sistema não consegue fornecer uma medição precisa do intervalo de tempo. Essa situação acontece na maioria dos casos em que a extensão da consulta é inferior a um dia ou em consultas de vários espaços de trabalho.

Importante

Este indicador apresenta apenas os dados processados no cluster imediato. Em uma consulta multirregião, ele representaria apenas uma das regiões. Em uma consulta com vários espaços de trabalho, ele pode não incluir todos os espaços de trabalho.

Idade dos dados tratados

O Azure Data Explorer usa várias camadas de armazenamento: na memória, discos SSD locais e Blobs do Azure muito mais lentos. Quanto mais novos os dados, maior a chance de serem armazenados em uma camada de maior desempenho com menor latência, o que reduz a duração da consulta e a CPU. Além dos dados em si, o sistema também tem um cache para metadados. Quanto mais antigos os dados, menor a chance de seus metadados estarem em um cache.

Uma consulta que processa dados com mais de 14 dias é considerada uma consulta que consome recursos excessivos.

Algumas consultas exigem o uso de dados antigos, mas também há casos em que dados antigos são usados por engano. Esse cenário acontece quando as consultas são executadas sem fornecer um intervalo de tempo em seus metadados e nem todas as referências de tabela incluem um filtro na TimeGenerated coluna. Nesses casos, o sistema verificará todos os dados armazenados na tabela. Quando a retenção de dados é longa, pode cobrir longos intervalos de tempo. Como resultado, os dados tão antigos quanto o período de retenção de dados são verificados.

Esses casos podem ser, por exemplo:

  • Não definir o intervalo de tempo no Log Analytics com uma subconsulta não limitada. Veja o exemplo anterior.
  • Usando a API sem os parâmetros opcionais do intervalo de tempo.
  • Usando um cliente que não força um intervalo de tempo, por exemplo, como o conector do Power BI.

Veja exemplos e notas na seção anterior, pois eles também são relevantes neste caso.

Número de regiões

Há situações em que uma única consulta pode ser executada em diferentes regiões. Por exemplo:

  • Quando vários espaços de trabalho estão explicitamente listados e estão localizados em regiões diferentes.
  • Quando uma consulta com escopo de recurso está buscando dados e os dados são armazenados em vários espaços de trabalho localizados em regiões diferentes.

A execução de consultas entre regiões requer que o sistema serialize e transfira no back-end grandes blocos de dados intermediários que geralmente são muito maiores do que os resultados finais da consulta. Também limita a capacidade do sistema de executar otimizações e heurísticas e usar caches.

Se não houver motivo para verificar todas essas regiões, ajuste o escopo para que ele abranja menos regiões. Se o escopo do recurso for minimizado, mas muitas regiões ainda forem usadas, isso pode acontecer devido a uma configuração incorreta. Por exemplo, logs de auditoria e configurações de diagnóstico podem ser enviados para espaços de trabalho diferentes em regiões diferentes ou pode haver várias configurações de definições de diagnóstico.

Uma consulta que abrange mais de três regiões é considerada uma consulta que consome recursos excessivos. Uma consulta que abrange mais de seis regiões é considerada uma consulta abusiva e pode ser limitada.

Importante

Quando uma consulta é executada em várias regiões, as medições da CPU e dos dados não serão precisas e representarão a medição de apenas uma das regiões.

Número de espaços de trabalho

Os espaços de trabalho são contêineres lógicos usados para segregar e administrar dados de logs. O back-end otimiza os posicionamentos do espaço de trabalho em clusters físicos dentro da região selecionada.

O uso de vários espaços de trabalho pode resultar de instâncias quando:

  • Vários espaços de trabalho são explicitamente listados.
  • Uma consulta com escopo de recursos está buscando dados e os dados são armazenados em vários espaços de trabalho.

A execução de consultas entre regiões e entre clusters requer que o sistema serialize e transfira no back-end grandes blocos de dados intermediários que geralmente são muito maiores do que os resultados finais da consulta. Também limita a capacidade do sistema de executar otimizações e heurísticas e usar caches.

Uma consulta que abrange mais de cinco espaços de trabalho é considerada uma consulta que consome recursos excessivos. As consultas não podem abranger mais de 100 espaços de trabalho.

Importante

  • Em alguns cenários de vários espaços de trabalho, as medições da CPU e dos dados não serão precisas e representarão a medição de apenas alguns dos espaços de trabalho.
  • As consultas entre espaços de trabalho com um identificador explícito: ID do espaço de trabalho ou ID do recurso do Azure do espaço de trabalho, consomem menos recursos e têm mais desempenho.

Paralelismo

Os Logs do Azure Monitor usam grandes clusters do Azure Data Explorer para executar consultas. Esses clusters variam em escala e potencialmente chegam a dezenas de nós de computação. O sistema dimensiona automaticamente os clusters de acordo com a lógica e a capacidade de posicionamento do espaço de trabalho.

Para executar uma consulta de forma eficiente, ela é particionada e distribuída para nós de computação com base nos dados necessários para seu processamento. Em algumas situações, o sistema não consegue fazer essa etapa de forma eficiente, o que pode levar a uma longa duração da consulta.

Os comportamentos de consulta que podem reduzir o paralelismo incluem:

  • Uso de funções de serialização e janela, como o operador serialize, next(), prev() e as funções de linha. Séries temporais e funções de análise de usuários podem ser usadas em alguns desses casos. A serialização ineficiente também pode acontecer se os seguintes operadores não forem usados no final da consulta: range, sort, order, top, top-hitters e getschema.
  • O uso da função de agregação dcount() força o sistema a ter uma cópia central dos valores distintos. Quando a escala de dados for alta, considere usar os parâmetros opcionais da função para reduzir a dcount precisão.
  • Em muitos casos, o operador de junção reduz o paralelismo geral. Examine shuffle join como alternativa quando o desempenho é problemático.
  • Em consultas de escopo de recursos, as verificações de controle de acesso baseado em função (RBAC) ou RBAC do Azure do Kubernetes de pré-execução podem permanecer em situações em que há um grande número de atribuições de função do Azure. Esta situação poderia conduzir a controlos mais longos, o que resultaria num paralelismo mais baixo. Por exemplo, uma consulta pode ser executada em uma assinatura onde há milhares de recursos e cada recurso tem muitas atribuições de função no nível de recurso, não na assinatura ou grupo de recursos.
  • Se uma consulta estiver processando pequenos blocos de dados, seu paralelismo será baixo porque o sistema não o espalhará por muitos nós de computação.

Próximos passos

Documentação de referência para o Kusto Query Language