Logboekquery's in Azure Monitor optimaliseren

Azure Monitor-logboeken maken gebruik van Azure Data Explorer om logboekgegevens op te slaan en query's uit te voeren voor het analyseren van die gegevens. Hiermee worden de Azure Data Explorer-clusters voor u gemaakt, beheerd en onderhouden en geoptimaliseerd voor uw workload voor logboekanalyse. Wanneer u een query uitvoert, wordt deze geoptimaliseerd en doorgestuurd naar het juiste Azure Data Explorer-cluster waarin de werkruimtegegevens worden opgeslagen.

Azure Monitor-logboeken en Azure Data Explorer gebruiken veel mechanismen voor automatische queryoptimalisatie. Automatische optimalisaties bieden een aanzienlijke boost, maar er zijn enkele gevallen waarin u de queryprestaties aanzienlijk kunt verbeteren. In dit artikel worden de prestatieoverwegingen en verschillende technieken beschreven om deze op te lossen.

De meeste technieken zijn gebruikelijk voor query's die rechtstreeks worden uitgevoerd in Azure Data Explorer en Azure Monitor-logboeken. Er worden ook verschillende unieke overwegingen voor Azure Monitor-logboeken besproken. Zie Best practices voor query's voor meer optimalisatietips voor Azure Data Explorer.

Geoptimaliseerde query's doen het volgende:

  • Voer sneller uit en verminder de totale duur van de uitvoering van de query.
  • Een kleinere kans hebben om te worden beperkt of afgewezen.

Let vooral op query's die worden gebruikt voor terugkerend en gelijktijdig gebruik, zoals dashboards, waarschuwingen, Azure Logic Apps en Power BI. De impact van een ineffectieve query in deze gevallen is aanzienlijk.

Hier volgt een gedetailleerd video-overzicht over het optimaliseren van query's.

Deelvenster Querydetails

Nadat u een query in Log Analytics hebt uitgevoerd, selecteert u querydetails in de rechterbenedenhoek van het scherm om het deelvenster Querydetails te openen. In dit deelvenster ziet u de resultaten van verschillende prestatie-indicatoren voor de query. Deze prestatie-indicatoren worden beschreven in de volgende sectie.

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

Prestatie-indicatoren voor query's

De volgende prestatie-indicatoren voor query's zijn beschikbaar voor elke query die wordt uitgevoerd:

  • Totale CPU: totale rekenkracht die wordt gebruikt voor het verwerken van de query op alle rekenknooppunten. Het vertegenwoordigt tijd die wordt gebruikt voor het berekenen, parseren en ophalen van gegevens.
  • Gegevens die worden gebruikt voor verwerkte query: Algemene gegevens die zijn geopend om de query te verwerken. Beïnvloed door de grootte van de doeltabel, de gebruikte tijdsduur, de toegepaste filters en het aantal kolommen waarnaar wordt verwezen.
  • Tijdsduur van de verwerkte query: de kloof tussen de nieuwste en de oudste gegevens die zijn geopend om de query te verwerken. Beïnvloed door het expliciete tijdsbereik dat is opgegeven voor de query.
  • Leeftijd van verwerkte gegevens: de kloof tussen nu en de oudste gegevens die zijn geopend om de query te verwerken. Het beïnvloedt de efficiëntie van het ophalen van gegevens sterk.
  • Aantal werkruimten: hoeveel werkruimten zijn geopend tijdens de queryverwerking op basis van impliciete of expliciete selectie.
  • Aantal regio's: hoeveel regio's zijn geopend tijdens de queryverwerking op basis van impliciete of expliciete selectie van werkruimten. Query's in meerdere regio's zijn veel minder efficiënt en prestatie-indicatoren vormen gedeeltelijke dekking.
  • Parallellisme: Geeft aan hoeveel het systeem deze query op meerdere knooppunten kan uitvoeren. Alleen relevant voor query's met een hoog CPU-verbruik. Beïnvloed door het gebruik van specifieke functies en operators.

Totale CPU

De werkelijke reken-CPU die is geïnvesteerd om deze query te verwerken op alle queryverwerkingsknooppunten. Omdat de meeste query's worden uitgevoerd op grote aantallen knooppunten, is dit totaal meestal veel groter dan de duur die de query heeft genomen om uit te voeren.

Een query die meer dan 100 seconden CPU gebruikt, wordt beschouwd als een query die overmatige resources verbruikt. Een query die meer dan 1000 seconden CPU gebruikt, wordt beschouwd als een beledigende query en kan worden beperkt.

De verwerkingstijd van query's wordt besteed aan:

  • Ophalen van gegevens: het ophalen van oude gegevens verbruikt meer tijd dan het ophalen van recente gegevens.
  • Gegevensverwerking: Logica en evaluatie van de gegevens.

Naast de tijd die is besteed aan de queryverwerkingsknooppunten, besteedt Azure Monitor-logboeken tijd aan:

  • De gebruiker verifiëren en controleren of ze toegang hebben tot deze gegevens.
  • Het gegevensarchief zoeken.
  • De query parseren.
  • De queryverwerkingsknooppunten toewijzen.

Deze keer is niet opgenomen in de totale CPU-tijd van de query.

Vroege filtering van records voorafgaand aan het gebruik van hoge CPU-functies

Sommige queryopdrachten en -functies zijn zwaar in hun CPU-verbruik. Dit geval geldt met name voor opdrachten die JSON en XML parseren of complexe reguliere expressies extraheren. Dergelijke parsering kan expliciet plaatsvinden via parse_json() of parse_xml() functies of impliciet wanneer deze verwijst naar dynamische kolommen.

Deze functies verbruiken CPU in verhouding tot het aantal rijen dat ze verwerken. De meest efficiënte optimalisatie is om vroeg in de query voorwaarden toe te voegen where . Op deze manier kunnen ze zoveel mogelijk records filteren voordat de CPU-intensieve functie wordt uitgevoerd.

De volgende query's produceren bijvoorbeeld precies hetzelfde resultaat. Maar de tweede is de meest efficiënte omdat de where-voorwaarde voordat parseren veel records uitsluit:

//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

Vermijd het gebruik van geëvalueerde waar-componenten

Query's die bevatten waar componenten voor een geëvalueerde kolom in plaats van op kolommen die fysiek aanwezig zijn in de gegevensset, verliezen efficiëntie. Filteren op geëvalueerde kolommen voorkomt dat bepaalde systeemoptimalisaties worden uitgevoerd wanneer grote gegevenssets worden verwerkt.

De volgende query's produceren bijvoorbeeld precies hetzelfde resultaat. Maar de tweede is efficiënter omdat de where-voorwaarde verwijst naar een ingebouwde kolom:

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

In sommige gevallen wordt de geëvalueerde kolom impliciet gemaakt door de queryverwerkingsengine, omdat het filteren niet alleen op het veld wordt uitgevoerd:

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

Effectieve aggregatieopdrachten en dimensies gebruiken in summarize en join

Sommige aggregatieopdrachten zoals max(), sum(), count()en avg() hebben een lage CPU-impact vanwege hun logica. Andere opdrachten zijn complexer en bevatten heuristieken en schattingen waarmee ze efficiënt kunnen worden uitgevoerd. Dcount() maakt bijvoorbeeld gebruik van het HyperLogLog-algoritme om een duidelijke schatting te geven van een uniek aantal grote gegevenssets zonder dat elke waarde daadwerkelijk wordt geteld.

De percentielfuncties doen vergelijkbare benaderingen met behulp van het dichtstbijzijnde percentiel-algoritme. Verschillende opdrachten bevatten optionele parameters om de impact ervan te verminderen. De functie makeset() heeft bijvoorbeeld een optionele parameter voor het definiëren van de maximale grootte van de set, wat van invloed is op de CPU en het geheugen.

Opdrachten samenvoegen en samenvatten kunnen leiden tot een hoog CPU-gebruik wanneer ze een grote set gegevens verwerken. Hun complexiteit is rechtstreeks gerelateerd aan het aantal mogelijke waarden, aangeduid als kardinaliteit, van de kolommen die worden gebruikt als de by in summarize - of als de join kenmerken. Zie de documentatieartikelen en optimalisatietips voor uitleg en optimalisatie van join en summarize.

De volgende query's produceren bijvoorbeeld precies hetzelfde resultaat, omdat CounterPath ze altijd een-op-een zijn toegewezen aan CounterName en ObjectName. De tweede is efficiënter omdat de aggregatiedimensie kleiner is:

//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

CPU-verbruik kan ook worden beïnvloed door where voorwaarden of uitgebreide kolommen waarvoor intensieve computing is vereist. Alle triviale tekenreeksvergelijkingen, zoals gelijk aan == en startswith, hebben ongeveer dezelfde CPU-impact. Geavanceerde tekstovereenkomsten hebben meer invloed. De has-operator is met name efficiënter dan de operator contains. Vanwege tekenreeksverwerkingstechnieken is het efficiënter om te zoeken naar tekenreeksen die langer zijn dan vier tekens dan korte tekenreeksen.

De volgende query's produceren bijvoorbeeld vergelijkbare resultaten, afhankelijk van Computer het naamgevingsbeleid. Maar de tweede is efficiënter:

//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 

Notitie

Deze indicator geeft alleen DE CPU van het onmiddellijke cluster weer. In een query met meerdere regio's vertegenwoordigt deze slechts één van de regio's. In een query met meerdere werkruimten zijn mogelijk niet alle werkruimten opgenomen.

Vermijd volledige XML- en JSON-parsering wanneer tekenreeksparsering werkt

Bij het volledig parseren van een XML- of JSON-object kunnen veel CPU- en geheugenbronnen worden verbruikt. Wanneer er in veel gevallen slechts één of twee parameters nodig zijn en de XML- of JSON-objecten eenvoudig zijn, is het eenvoudiger om ze te parseren als tekenreeksen. Gebruik de parseringsoperator of andere technieken voor het parseren van tekst. De prestatieverhoging is belangrijker omdat het aantal records in het XML- of JSON-object toeneemt. Het is essentieel wanneer het aantal records tientallen miljoenen bereikt.

De volgende query retourneert bijvoorbeeld precies dezelfde resultaten als de voorgaande query's zonder volledige XML-parsering uit te voeren. In de query worden enkele veronderstellingen over de STRUCTUUR van het XML-bestand gemaakt, zoals het FilePath element erna FileHash komt en geen van deze elementen kenmerken heeft:

//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

Gegevens die worden gebruikt voor verwerkte query's

Een belangrijke factor bij de verwerking van de query is het volume gegevens dat wordt gescand en gebruikt voor de queryverwerking. Azure Data Explorer maakt gebruik van agressieve optimalisaties die het gegevensvolume aanzienlijk verminderen ten opzichte van andere gegevensplatforms. Er zijn echter kritieke factoren in de query die van invloed kunnen zijn op het gebruikte gegevensvolume.

Een query die meer dan 2000 kB aan gegevens verwerkt, wordt beschouwd als een query die overmatige resources verbruikt. Een query die meer dan 20.000 KB aan gegevens verwerkt, wordt beschouwd als een beledigende query en kan worden beperkt.

In Azure Monitor-logboeken wordt de TimeGenerated kolom gebruikt als een manier om de gegevens te indexeren. Als u de TimeGenerated waarden beperkt tot een zo beperkt mogelijk bereik, worden de queryprestaties verbeterd. Het smalle bereik beperkt de hoeveelheid gegevens die moet worden verwerkt.

Vermijd onnodig gebruik van zoek- en samenvoegoperators

Een andere factor die de verwerkte gegevens verhoogt, is het gebruik van een groot aantal tabellen. Dit scenario treedt meestal op wanneer search * en union * opdrachten worden gebruikt. Met deze opdrachten dwingt u af dat het systeem gegevens uit alle tabellen in de werkruimte evalueert en scant. In sommige gevallen zijn er mogelijk honderden tabellen in de werkruimte. Vermijd het gebruik search * van een zoekopdracht of zoekactie zonder het bereik ervan te beperken tot een specifieke tabel.

De volgende query's produceren bijvoorbeeld precies hetzelfde resultaat, maar de laatste is het meest efficiënt:

// 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

Vroege filters toevoegen aan de query

Een andere methode om het gegevensvolume te verminderen, is om de omstandigheden vroeg in de query te hebben. Het Azure Data Explorer-platform bevat een cache waarmee wordt aangegeven welke partities gegevens bevatten die relevant zijn voor een specifieke where voorwaarde. Als een query bijvoorbeeld een query bevat where EventID == 4624, wordt de query alleen gedistribueerd naar knooppunten die partities verwerken met overeenkomende gebeurtenissen.

De volgende voorbeeldquery's produceren precies hetzelfde resultaat, maar de tweede query is efficiënter:

//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

Vermijd meerdere scans van dezelfde brongegevens met behulp van voorwaardelijke aggregatiefuncties en de materialisatiefunctie

Wanneer een query meerdere subquery's bevat die worden samengevoegd met behulp van join- of samenvoegoperators, scant elke subquery de hele bron afzonderlijk. Vervolgens worden de resultaten samengevoegd. Met deze actie wordt het aantal keren vermenigvuldigd dat gegevens worden gescand. Dit is een kritieke factor in grote gegevenssets.

Een techniek om dit scenario te voorkomen, is door gebruik te maken van de voorwaardelijke aggregatiefuncties. De meeste aggregatiefuncties die worden gebruikt in een samenvattingsoperator hebben een geconditioneerde versie die u kunt gebruiken voor één samenvattende operator met meerdere voorwaarden.

In de volgende query's ziet u bijvoorbeeld het aantal aanmeldingsevenementen en het aantal procesuitvoeringsevenementen voor elk account. Ze retourneren dezelfde resultaten, maar de eerste query scant de gegevens twee keer. De tweede query scant deze slechts één keer:

//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

Een ander geval waarbij subquery's niet nodig zijn, is het vooraf filteren van een parseringsoperator om ervoor te zorgen dat alleen records worden verwerkt die overeenkomen met een specifiek patroon. Ze zijn niet nodig omdat de parseringsoperator en andere vergelijkbare operators lege resultaten retourneren wanneer het patroon niet overeenkomt. De volgende twee query's retourneren precies dezelfde resultaten, maar de tweede query scant de gegevens slechts één keer. In de tweede query is elke parseringsopdracht alleen relevant voor de gebeurtenissen. De extend operator laat daarna zien hoe u naar een lege gegevenssituatie verwijst:

//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

Wanneer u met de voorgaande query geen subquery's kunt gebruiken, is een andere techniek om aan te geven aan de query-engine dat er één gegevensbron is die in elk van deze query's wordt gebruikt met behulp van de functie materialize(). Deze techniek is handig wanneer de brongegevens afkomstig zijn van een functie die meerdere keren in de query wordt gebruikt. Materialize is effectief wanneer de uitvoer van de subquery veel kleiner is dan de invoer. De query-engine slaat de uitvoer in de cache op en hergebruikt de uitvoer in alle gevallen.

Het aantal kolommen verminderen dat wordt opgehaald

Omdat Azure Data Explorer een kolomgegevensarchief is, is het ophalen van elke kolom onafhankelijk van de andere. Het aantal kolommen dat rechtstreeks wordt opgehaald, heeft rechtstreeks invloed op het totale gegevensvolume. U moet alleen de kolommen opnemen in de uitvoer die nodig zijn door de resultaten samen te vatten of de specifieke kolommen te projecteren .

Azure Data Explorer heeft verschillende optimalisaties om het aantal opgehaalde kolommen te verminderen. Als wordt bepaald dat een kolom niet nodig is, bijvoorbeeld als er niet naar wordt verwezen in de opdracht Samenvatten , wordt deze niet opgehaald.

De tweede query kan bijvoorbeeld drie keer meer gegevens verwerken omdat deze niet één kolom maar drie moet ophalen:

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

Tijdsduur van de verwerkte query

Alle logboeken in Azure Monitor-logboeken worden gepartitioneerd op basis van de TimeGenerated kolom. Het aantal partities dat wordt geopend, is rechtstreeks gerelateerd aan de periode. Het verkorten van het tijdsbereik is de meest efficiënte manier om een promptquery-uitvoering te garanderen.

Een query met een tijdsduur van meer dan 15 dagen wordt beschouwd als een query die overmatige resources verbruikt. Een query met een tijdsduur van meer dan 90 dagen wordt beschouwd als een beledigende query en kan worden beperkt.

U kunt het tijdsbereik instellen met behulp van de tijdsbereikkiezer in het Log Analytics-scherm, zoals beschreven in het bereik en tijdsbereik van logboeken in Azure Monitor Log Analytics. Deze methode wordt aanbevolen omdat het geselecteerde tijdsbereik wordt doorgegeven aan de back-end met behulp van de metagegevens van de query.

Een alternatieve methode is om expliciet een where-voorwaardeTimeGenerated op te nemen in de query. Gebruik deze methode omdat de tijdsduur is opgelost, zelfs wanneer de query wordt gebruikt vanuit een andere interface.

Zorg ervoor dat alle onderdelen van de query filters hebben TimeGenerated . Wanneer een query subquery's bevat die gegevens ophalen uit verschillende tabellen of dezelfde tabel, moet elke query een eigen where-voorwaarde bevatten.

Zorg ervoor dat alle subquery's het filter TimeGenerated hebben

In de volgende query wordt de Perf tabel bijvoorbeeld alleen gescand op de laatste dag. De Heartbeat tabel wordt gescand op alle geschiedenis, die maximaal twee jaar kan duren:

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

Een veelvoorkomend geval waarin een dergelijke fout optreedt, is wanneer arg_max() wordt gebruikt om het meest recente exemplaar te vinden. Bijvoorbeeld:

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

U kunt deze situatie eenvoudig corrigeren door een tijdfilter toe te voegen aan de binnenste query:

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

Een ander voorbeeld van deze fout is wanneer u het tijdsbereik filtert vlak na een samenvoeging over verschillende tabellen. Wanneer u de samenvoeging uitvoert, moet elke subquery binnen het bereik vallen. U kunt een let-instructie gebruiken om een bereikconsistentie te garanderen.

Met de volgende query worden bijvoorbeeld alle gegevens in de Heartbeat en Perf tabellen gescand, niet alleen op de laatste dag:

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

Ga als volgt te werk om de query op te lossen:

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

Beperkingen voor tijdspannemeting

De meting is altijd groter dan de werkelijke tijd die is opgegeven. Als het filter op de query bijvoorbeeld 7 dagen is, scant het systeem 7,5 of 8,1 dagen. Deze variantie komt doordat het systeem de gegevens partitioneert in segmenten van variabelegrootten. Om ervoor te zorgen dat alle relevante records worden gescand, scant het systeem de volledige partitie. Dit proces kan enkele uren en zelfs meer dan een dag omvatten.

Er zijn verschillende gevallen waarin het systeem geen nauwkeurige meting van het tijdsbereik kan bieden. Deze situatie treedt in de meeste gevallen op wanneer de duur van de query minder is dan een dag of in query's met meerdere werkruimten.

Belangrijk

Deze indicator geeft alleen gegevens weer die in het onmiddellijke cluster worden verwerkt. In een query met meerdere regio's vertegenwoordigt deze slechts één van de regio's. In een query met meerdere werkruimten zijn mogelijk niet alle werkruimten opgenomen.

Leeftijd van verwerkte gegevens

Azure Data Explorer maakt gebruik van verschillende opslaglagen: in-memory, lokale SSD-schijven en veel tragere Azure-blobs. Hoe hoger de gegevens, hoe hoger de kans dat deze worden opgeslagen in een beter presterende laag met kleinere latentie, waardoor de queryduur en CPU worden verminderd. Behalve de gegevens zelf heeft het systeem ook een cache voor metagegevens. Hoe ouder de gegevens, hoe minder kans de metagegevens zich in een cache bevinden.

Een query die gegevens verwerkt die meer dan 14 dagen oud zijn, wordt beschouwd als een query die overmatige resources verbruikt.

Voor sommige query's is het gebruik van oude gegevens vereist, maar er zijn ook gevallen waarin oude gegevens per ongeluk worden gebruikt. Dit scenario treedt op wanneer query's worden uitgevoerd zonder een tijdsbereik in hun metagegevens op te geven en niet alle tabelverwijzingen een filter op de TimeGenerated kolom bevatten. In deze gevallen scant het systeem alle gegevens die in de tabel zijn opgeslagen. Wanneer de gegevensretentie lang is, kan dit lange tijdsbereiken omvatten. Als gevolg hiervan worden gegevens gescand die net zo oud zijn als de gegevensretentieperiode.

Dergelijke gevallen kunnen bijvoorbeeld zijn:

  • Het tijdsbereik niet instellen in Log Analytics met een subquery die niet beperkt is. Zie het voorgaande voorbeeld.
  • Gebruik de API zonder de optionele parameters voor het tijdsbereik.
  • Een client gebruiken die bijvoorbeeld geen tijdsbereik afdingt, zoals de Power BI-connector.

Bekijk voorbeelden en notities in de vorige sectie, omdat deze ook relevant zijn in dit geval.

Aantal regio's

Er zijn situaties waarin één query kan worden uitgevoerd in verschillende regio's. Bijvoorbeeld:

  • Wanneer verschillende werkruimten expliciet worden vermeld en zich in verschillende regio's bevinden.
  • Wanneer een query met resourcebereik gegevens ophaalt en de gegevens worden opgeslagen in meerdere werkruimten die zich in verschillende regio's bevinden.

Voor het uitvoeren van query's in meerdere regio's moet het systeem grote segmenten tussenliggende gegevens serialiseren en overdragen die meestal veel groter zijn dan de uiteindelijke resultaten van de query. Het beperkt ook de mogelijkheid van het systeem om optimalisaties en heuristieken uit te voeren en caches te gebruiken.

Als er geen reden is om al deze regio's te scannen, past u het bereik aan zodat het minder regio's omvat. Als het resourcebereik is geminimaliseerd, maar er nog steeds veel regio's worden gebruikt, kan dit gebeuren vanwege een onjuiste configuratie. Auditlogboeken en diagnostische instellingen kunnen bijvoorbeeld worden verzonden naar verschillende werkruimten in verschillende regio's of er zijn meerdere configuraties voor diagnostische instellingen.

Een query die meer dan drie regio's omvat, wordt beschouwd als een query die overmatige resources verbruikt. Een query die meer dan zes regio's omvat, wordt beschouwd als een beledigende query en kan worden beperkt.

Belangrijk

Wanneer een query wordt uitgevoerd in verschillende regio's, zijn de CPU- en gegevensmetingen niet nauwkeurig en worden de metingen van slechts één van de regio's vertegenwoordigd.

Aantal werkruimten

Werkruimten zijn logische containers die worden gebruikt om logboekgegevens te scheiden en te beheren. De back-end optimaliseert de plaatsing van werkruimten op fysieke clusters binnen de geselecteerde regio.

Het gebruik van meerdere werkruimten kan het gevolg zijn van exemplaren wanneer:

  • Verschillende werkruimten worden expliciet vermeld.
  • Een query met resourcebereik haalt gegevens op en de gegevens worden opgeslagen in meerdere werkruimten.

Voor het uitvoeren van query's tussen regio's en meerdere clusters moet het systeem grote segmenten tussenliggende gegevens serialiseren en overdragen in de back-end die meestal veel groter zijn dan de uiteindelijke resultaten van de query. Het beperkt ook de mogelijkheid van het systeem om optimalisaties en heuristieken uit te voeren en caches te gebruiken.

Een query die meer dan vijf werkruimten omvat, wordt beschouwd als een query die overmatige resources verbruikt. Query's kunnen niet meer dan 100 werkruimten omvatten.

Belangrijk

  • In sommige scenario's met meerdere werkruimten zijn de CPU- en gegevensmetingen niet nauwkeurig en vertegenwoordigen ze de meting van slechts enkele werkruimten.
  • Query's voor meerdere werkruimten met een expliciete id: werkruimte-id of Azure-resource-id voor werkruimten, verbruiken minder resources en presteren beter.

Parallelle uitvoering

Azure Monitor-logboeken maken gebruik van grote clusters van Azure Data Explorer om query's uit te voeren. Deze clusters variëren in schaal en kunnen maximaal tientallen rekenknooppunten bevatten. Het systeem schaalt de clusters automatisch op basis van de plaatsingslogica en capaciteit van de werkruimte.

Om een query efficiënt uit te voeren, wordt deze gepartitioneerd en gedistribueerd naar rekenknooppunten op basis van de gegevens die nodig zijn voor de verwerking ervan. In sommige situaties kan dit systeem deze stap niet efficiënt uitvoeren, wat kan leiden tot een lange duur van de query.

Querygedrag dat parallellisme kan verminderen, zijn onder andere:

  • Gebruik van serialisatie- en vensterfuncties, zoals de serialisatieoperator, next(), prev()en de rijfuncties . Tijdreeks- en gebruikersanalysefuncties kunnen in sommige van deze gevallen worden gebruikt. Inefficiënte serialisatie kan ook optreden als de volgende operators niet worden gebruikt aan het einde van de query: bereik, sortering, volgorde, top, top-hitters en getschema.
  • Het gebruik van de aggregatiefunctie dcount() dwingt het systeem om een centrale kopie van de afzonderlijke waarden te hebben. Wanneer de schaal van gegevens hoog is, kunt u overwegen de optionele parameters van de functie te gebruiken om de dcount nauwkeurigheid te verminderen.
  • In veel gevallen verlaagt de join-operator de algehele parallelle uitvoering. Onderzoek shuffle join als alternatief wanneer de prestaties problematisch zijn.
  • In query's voor resourcebereik kunnen de op rollen gebaseerd toegangsbeheer (RBAC) van Kubernetes of Azure RBAC-controles vóór uitvoering achterblijven in situaties waarin er een groot aantal Azure-roltoewijzingen is. Deze situatie kan leiden tot langere controles die leiden tot een lagere parallelle uitvoering. Een query kan bijvoorbeeld worden uitgevoerd op een abonnement waarin duizenden resources zijn en elke resource veel roltoewijzingen op resourceniveau heeft, niet voor het abonnement of de resourcegroep.
  • Als een query kleine segmenten gegevens verwerkt, is de parallelle uitvoering laag omdat het systeem deze niet over veel rekenknooppunten verspreidt.

Volgende stappen

Referentiedocumentatie voor de Kusto-querytaal