Consultas de log no Azure Monitor
Os Logs do Azure Monitor usam o Azure Data Explorer para armazenar os dados de log e executar as consultas para analisar esses dados. Cria, gerencia e mantém os clusters do Azure Data Explorer, otimizando-os para a carga de trabalho de análise de log. Quando você executa uma consulta, ela é otimizada e encaminhada ao cluster do Azure Data Explorer apropriado que armazena os dados do workspace.
Os Logs do Azure Monitor e o Azure Data Explorer usam vários mecanismos automáticos de otimização de consulta. As otimizações automáticas oferecem um aprimoramento significativo, mas há alguns casos em que você pode aprimorar consideravelmente o desempenho da consulta. Este artigo explica as considerações de desempenho e as várias técnicas para corrigi-los.
A maioria das técnicas são comuns para consultas executadas diretamente no Azure Data Explorer e nos Logs do Azure Monitor. Várias considerações exclusivas dos Logs do Azure Monitor também são discutidas. Para obter mais dicas sobre a otimização do Azure Data Explorer, consulte Melhores práticas de consulta.
As consultas otimizadas:
- São executadas com mais rapidez, reduzindo a duração geral da execução da consulta.
- Terão menor possibilidade de serem rejeitadas ou limitadas.
Atente-se principalmente às consultas usadas de modo recorrente e simultâneo como as de painéis, de alertas, de Aplicativos Lógicos do Azure e do Power BI. Nesses casos, o impacto de uma consulta ineficaz é significativo.
Veja um vídeo de explicação passo a passo sobre a otimização de 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. Esse painel mostra os resultados de vários indicadores de desempenho para a consulta. Esses indicadores de desempenho são descritos na seção a seguir.
Indicadores de desempenho de consulta
Os seguintes indicadores de desempenho de consulta estão disponíveis para cada consulta executada:
- Total de CPU: computação geral usada para processar a consulta em todos os nós de computação. Representa o tempo usado para computação, análise e busca de dados.
- Dados usados para consulta processada: dados gerais que foram acessados para processar a consulta. É influenciado pelo tamanho da tabela de destino, pelo período de tempo usado, pelos filtros aplicados e pelos número de colunas referenciadas.
- Período de tempo da consulta processada: a lacuna entre os dados mais recentes e os dados mais antigos que foram acessados para processar a consulta. Influenciado pelo intervalo de tempo explícito especificado para a consulta.
- Idade dos dados processados: a lacuna entre os dados atuais e os dados mais antigos que foram acessados para processar a consulta. Isso influencia muito a eficiência da busca de dados.
- Número de workspaces: quantos workspaces foram acessados durante o processamento da consulta com base na seleção implícita ou explícita.
- Número de regiões: quantas regiões foram acessadas durante o processamento da consulta com base na seleção implícita ou explícita de workspaces. Consultas a várias regiões são muito menos eficientes e os indicadores de desempenho apresentam cobertura parcial.
- Paralelismo: indica o quanto o sistema pôde executar esta consulta em vários nós. Relevante apenas para consultas com alto nível de consumo de CPU. Influenciado pelo uso de funções e operadores específicos.
Total de 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 será muito maior do que a duração da execução da consulta.
A consulta que usa mais de 100 segundos de CPU é considerada uma consulta que consome recursos excessivos. A consulta que usa mais de 1.000 segundos de CPU é considerada uma consulta abusiva e pode ser limitada.
O tempo de processamento da consulta é gasto em:
- Recuperação de dados: a recuperação de dados antigos consumirá mais tempo do que a recuperação de dados recentes.
- Processamento de dados: lógica e avaliação dos dados.
Além do tempo gasto nos nós de processamento de consulta, os Logs do Azure Monitor gastam tempo para:
- Autenticar o usuário e verificar se ele tem permissão para acessar esses dados.
- Localizar o armazenamento de dados.
- Analisar a consulta.
- Alocar os nós de processamento de consulta.
Esse tempo não é incluído no tempo total de CPU da consulta.
Filtragem antecipada de registros antes de usar funções com alto uso de CPU
Alguns dos comandos e das funções de consulta geram o consumo intenso de CPU. Esse caso ocorre principalmente com comandos que analisam JSON e XML ou extraem expressões regulares complexas. Essa análise pode acontecer explicitamente por meio das funções parse_json() ou parse_xml() ou implicitamente ao se referir a colunas dinâmicas.
Essas funções consomem CPU em proporção ao número de linhas sendo processadas. A otimização mais eficiente é adicionar condições where
no início da consulta. Dessa forma, elas podem filtrar o máximo de registros possível antes que a função com uso intensivo de CPU seja executada.
Por exemplo, as consultas a seguir produzem exatamente o mesmo resultado. Mas a segunda opção é a mais eficiente porque a condição where exclui vários registros antes da análise:
//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 where avaliadas
Consultas contendo cláusulas where em uma coluna avaliada, em vez de colunas fisicamente presentes no conjunto de dados, perdem eficiência. A filtragem em colunas avaliadas evita algumas otimizações do sistema quando grandes conjuntos de dados são tratados.
Por exemplo, as consultas a seguir produzem exatamente o mesmo resultado. Mas a segunda opção é a mais eficiente porque a condição where se refere a uma coluna interna:
//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 consulta, pois 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
Usar comandos e dimensões de agregação eficazes para resumir e unir
Alguns comandos de agregação como max(), sum(), count() e avg() têm baixo impacto na CPU devido à lógica. Outros comandos são mais complexos e incluem heurísticas e estimativas que permitem que eles sejam executados com eficiência. Por exemplo, dcount() usa o algoritmo HyperLogLog para fornecer uma boa estimativa de uma contagem distinta de conjuntos de dados grandes sem realmente contar cada valor.
As funções de percentil fazem aproximações semelhantes usando o algoritmo de percentil de classificação mais próxima. Vários dos comandos incluem parâmetros opcionais para reduzir o 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 join e summarize podem causar alto uso de CPU ao processar um grande conjunto de dados. A complexidade está diretamente relacionada ao número de valores possíveis, chamados de cardinalidade, das colunas que são usadas como o by
em summarize
ou como os atributos join
. Para obter uma explicação e uma otimização de join
e summarize
, confira os respectivos artigos de documentação e as dicas de otimização.
Por exemplo, as consultas a seguir produzem exatamente o mesmo resultado porque CounterPath
é sempre mapeado um a um para CounterName
e ObjectName
. O segundo é 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 de CPU também pode ser afetado pelas condições where
ou colunas estendidas que exigem uso intensivo de computação. Todas as comparações de cadeia de caracteres, como equal == and startswith, tem quase o mesmo impacto na CPU. As correspondências de texto avançadas têm mais impacto. Especificamente, o operador has é mais eficiente que o operador contains. Devido às técnicas de manipulação de cadeias de caracteres, é mais eficiente procurar cadeias de caracteres com mais de quatro caracteres do que as menores.
Por exemplo, as consultas a seguir geram resultados semelhantes, dependendo da política de nomenclatura de Computer
. Mas a segunda opção é 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
Observação
Este indicador apresenta apenas CPU do cluster imediato. Em uma consulta a várias regiões, ele representaria apenas uma das regiões. Em uma consulta a vários workspaces, ele poderia não incluir todos os workspaces.
Evite a análise completa de XML e JSON quando a análise de cadeia de caracteres funcionar
A análise completa de um objeto XML ou JSON pode consumir muitos recursos de CPU e memória. Em muitos casos, somente quando 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 parse ou outras técnicas de análise de texto. O aumento de desempenho será mais significativo à medida que o número de registros no objeto XML ou JSON aumentar. Isso será fundamental quando o número de registros alcançar dezenas de milhões.
Por exemplo, a consulta a seguir retornará exatamente os mesmos resultados que as consultas acima, sem realizar uma análise de XML completa. A consulta faz algumas suposições sobre a estrutura do arquivo XML, como se o elemento FilePath
vem após o FileHash
e se 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 usados para consulta processada
Um fator crítico no processamento da consulta é o volume de dados que é examinado 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.
A consulta que processa mais de 2.000 KB de dados é considerada uma consulta que consome recursos excessivos. A consulta que processa mais de 20.000 KB de dados é considerada uma consulta abusiva e pode ser limitada.
Nos Logs do Azure Monitor, a coluna TimeGenerated
é usada como uma forma para indexar os dados. A restrição dos valores de TimeGenerated
ao menor intervalo possível aprimora o desempenho da consulta. O intervalo menor limita significativamente a quantidade de dados que precisam ser processados.
Evite usar desnecessariamente os operadores de união e de pesquisa
Outro fator que aumenta os dados que serão processados é o uso de um grande número de tabelas. Esse cenário geralmente acontece quando os comandos search *
e union *
são usados. Esses comandos forçam o sistema a avaliar e examinar os 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 de search *
ou de qualquer pesquisa sem definir o escopo para uma tabela específica.
Por exemplo, as seguintes consultas produzem exatamente o mesmo resultado, mas a segunda é 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 iniciais à consulta
Outro método para reduzir o volume de dados é ter condições where 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 where
específica. Por exemplo, se uma consulta contiver where EventID == 4624
, essa opção distribuirá a consulta apenas para nós que processam partições com eventos correspondentes.
As seguintes consultas de exemplo produzem exatamente o mesmo resultado, mas a segunda é a 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 examinar várias vezes os mesmos dados de origem usando as funções de agregação condicional e a função materializar
Quando uma consulta tem várias subconsultas mescladas por operadores de junção ou de união, cada subconsulta examina toda a origem separadamente. Depois, ela mescla os resultados. Essa ação multiplica o número de vezes que os dados são examinados, o que é um fator crítico em grandes conjuntos de dados.
Uma técnica para evitar esse cenário é usar as funções de agregação condicional. A maioria das funções de agregação que são usadas em um operador de resumo tem uma versão condicionada para usar um só operador de resumo com várias condições.
Por exemplo, as consultas a seguir mostram o número de eventos de logon e o número de eventos de execução de processo para cada conta. Elas retornam os mesmos resultados, mas a primeira consulta examina os dados duas vezes. A segunda consulta examina-os 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 é durante a pré-filtragem do operador parse para garantir que ele processe apenas os registros que correspondem a um padrão específico. Elas são desnecessárias, pois o operador parse 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 examina os dados apenas uma vez. Na segunda consulta, cada comando de análise é relevante apenas para os eventos. Depois, o operador extend
mostra 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 evitar o uso de subconsultas, outra técnica é sugerir ao mecanismo de consulta que há uma só fonte de dados usada em cada uma delas com a função materialize(). Essa técnica é útil quando os dados de origem são provenientes de uma função que é 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. É necessário somente incluir as colunas desejadas na saída, resumindo os resultados ouprojetando 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 será recuperada.
Por exemplo, a segunda consulta pode processar três vezes mais dados, já que ela precisa três colunas em vez de apenas uma:
//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 do Azure Monitor são particionados de acordo com a coluna TimeGenerated
. O número de partições acessadas está diretamente relacionado ao período de tempo. Reduzir o intervalo de tempo é a maneira mais eficiente de garantir a execução imediata da consulta.
A consulta com período de tempo acima de 15 dias é considerada uma consulta que consome recursos excessivos. A consulta com período de tempo acima de 90 dias é considerada uma consulta abusiva e pode ser limitada.
O intervalo de tempo pode ser definido usando o seletor de intervalo de tempo na tela do Log Analytics, conforme a descrição em Escopo de consulta de log e intervalo de tempo no Log Analytics do Azure Monitor. Esse método é recomendado porque o intervalo de tempo selecionado é passado para o back-end usando metadados de consulta.
Um método alternativo é incluir explicitamente uma condição where na consultaTimeGenerated
. Use esse método, pois ele garante que o intervalo de tempo seja fixo, mesmo quando a consulta é usada por meio de uma interface diferente.
Verifique se todas as partes da consulta têm filtros TimeGenerated
. Quando uma consulta tem subconsultas que buscam dados de várias tabelas ou da mesma tabela, cada uma precisa incluir a própria condição where.
Verifique se todas as subconsultas têm o filtro TimeGenerated
Por exemplo, na consulta a seguir, a tabela Perf
será examinada somente em relação ao último dia. A tabela Heartbeat
será examinada em relação a todo o 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 esse 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
É fácil corrigir 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 é ao realizar a filtragem do escopo de tempo logo após uma união de várias tabelas. Para realizar a união, cada subconsulta deve ter o escopo definido. É possível usar a instrução let para garantir a consistência do escopo.
Por exemplo, a consulta a seguir examinará todos os dados nas tabelas Heartbeat
e Perf
, não apenas em relação ao ú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 período de tempo
A medição é sempre maior do que o tempo real especificado. Por exemplo, se o filtro da consulta for de 7 dias, o sistema poderá fazer o exame de 7,5 ou 8,1 dias. Essa variação ocorre porque o sistema particiona os dados em partes de tamanhos variados. Para garantir que todos os registros relevantes sejam examinados, o sistema examina a partição inteira. Esse processo pode durar várias horas e até mais de um dia.
Há diversos 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 consulta dura menos de um dia ou em consultas com vários workspaces.
Importante
Este indicador apresenta apenas dados processados no cluster imediato. Em uma consulta a várias regiões, ele representaria apenas uma das regiões. Em uma consulta a vários workspaces, ele poderia não incluir todos os workspaces.
Idade dos dados processados
O Azure Data Explorer usa várias camadas de armazenamento: na memória, discos SSD locais e Blobs do Azure, que são muito mais lentos. Quanto mais novos forem os dados, maior será a possibilidade de que eles sejam armazenados em uma camada de melhor desempenho e menor latência, que reduz a duração da consulta e o uso de CPU. Além dos próprios dados, o sistema também possui um cache para metadados. Quanto mais antigos forem os dados, menor será a possibilidade de que os metadados sejam armazenados em cache.
É considerado que uma consulta que processa dados com mais de 14 dias consome recursos em excesso.
Embora algumas consultas exijam o uso de dados antigos, há casos em que eles são usados por engano. Esse cenário acontece quando as consultas são executadas sem fornecer o intervalo de tempo nos metadados e nem todas as referências de tabela incluem um filtro na coluna TimeGenerated
. Nesses casos, o sistema examinará todos os dados armazenados nessa tabela. Quando a retenção de dados é longa, ela pode abranger longos intervalos de tempo. Como resultado, são verificados os dados tão antigos quanto o período de retenção de dados.
Esses casos podem ser, por exemplo:
- Não definir o intervalo de tempo no Log Analytics com uma subconsulta que não seja limitada. Confira o exemplo anterior.
- Usar a API sem os parâmetros opcionais de intervalo de tempo.
- O uso de um cliente que não force um intervalo de tempo, como o conector do Power BI.
Veja os exemplos e as observações na seção anterior, que também são relevantes nesse caso.
Número de regiões
Há situações em que uma só consulta pode ser executada em diferentes regiões. Por exemplo:
- Quando vários workspaces são listados explicitamente 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 diferentes regiões.
A execução de consulta entre regiões exige que o sistema serialize e transfira no back-end grandes partes de dados intermediários que costumam ser muito maiores do que os resultados finais da consulta. Também limita a capacidade do sistema de realizar otimizações e heurísticas e de usar caches.
Se não houver um motivo para examinar todas essas regiões, ajuste o escopo para abranger menos regiões. Se o escopo do recurso for minimizado, mas muitas regiões ainda forem usadas, o motivo poderá ser uma configuração incorreta. Por exemplo, os logs de auditoria e as configurações de diagnóstico podem ser enviados para diferentes workspaces em diferentes regiões ou pode haver várias definições de configuração de diagnóstico.
A consulta que abrange mais de três regiões é considerada uma consulta que consome recursos excessivos. A 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 de CPU e de dados não são precisas e representam 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 separar e administrar os dados de logs. O back-end otimiza os posicionamentos de workspace em clusters físicos dentro da região selecionada.
O uso de vários workspaces pode resultar de instâncias quando:
- Vários workspaces são listados explicitamente.
- Quando uma consulta com escopo de recurso busca dados e os dados são armazenados em vários workspace.
A execução de consultas entre regiões e entre clusters exige que o sistema serialize e transfira no back-end grandes partes 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 realizar otimizações e heurísticas e de usar caches.
A consulta que abrange mais de cinco workspaces é considerada uma consulta que consome recursos excessivos. As consultas não podem abranger mais de 100 workspaces.
Importante
- Em alguns cenários de vários workspaces, as medições de CPU e de dados não são precisas e representam a medição de apenas alguns dos workspaces.
- As consultas entre espaços de trabalho com um identificador explícito, ID do espaço de trabalho ou ID de Recurso do Azure do espaço de trabalho, consomem menos recursos e têm um desempenho maior.
Paralelismo
Os Logs do Azure Monitor usam clusters grandes do Azure Data Explorer para executar consultas. Esses clusters variam em escala e podem chegar 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 que uma consulta seja executada com eficiência, ela é particionada e distribuída aos nós de computação com base nos dados necessários para o processamento. Em algumas situações, o sistema não pode executar essa etapa com eficiência, o que pode causar uma longa duração da consulta.
Os comportamentos de consulta que podem reduzir o paralelismo incluem:
- O uso de serialização e de funções de janela, como o operador serialize, next(), prev() e as funções row. As séries temporais e as funções de análise do usuário podem ser usadas em alguns desses casos. A serialização ineficiente também pode acontecer quando os seguintes operadores não são 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, use os parâmetros opcionais da função
dcount
para reduzir a precisão. - Em muitos casos, o operador join reduz o paralelismo geral. Examine
shuffle join
como uma alternativa quando houver problemas de desempenho. - Em consultas com escopo de recurso, as verificações de pré-execução de RBAC (controle de acesso baseado em função)do Kubernetes ou de RBAC do Azure podem demorar quando há um grande número de atribuições de função do Azure. Essa situação pode gerar verificações mais longas, diminuindo o paralelismo. Por exemplo, uma consulta é executada em uma assinatura em que há milhares de recursos e cada recurso tem várias atribuições de função no nível do recurso, não da assinatura ou do grupo de recursos.
- Se uma consulta estiver processando pequenas partes de dados, o paralelismo será baixo, pois o sistema não os espalhará em muitos nós de computação.