Logquery's optimaliseren in Azure Monitor

Azure Monitor Logs is een volledig beheerde, cloudschaalservice die is ontworpen voor het automatisch verwerken van opname, indexering en query’s over grote en fluctuerende workloads. De onderliggende engine maakt gebruik van ingebouwde mechanismen voor het optimaliseren van de uitvoering van query's, het distribueren van de verwerking en het automatisch schalen van resources zonder tussenkomst van de gebruiker.

Azure Monitor Logs maakt gebruik van Azure Data Explorer als onderdeel van de onderliggende engine om logboekgegevens op te slaan en query's uit te voeren om die gegevens te analyseren. Het maakt, beheert en onderhoudt de Azure Data Explorer clusters voor u en optimaliseert deze voor uw logboekanalyseworkloads. Wanneer u een query uitvoert, optimaliseert de service deze en stuurt deze door naar het juiste Azure Data Explorer cluster waarin de werkruimtegegevens worden opgeslagen.

Azure Monitor Logs en Azure Data Explorer gebruiken veel mechanismen voor automatische queryoptimalisatie. Net als bij elk groot analytisch systeem vereist het uitvoeren van query's in zeer grote gegevenssets extra rekenresources en kan dit van invloed zijn op de prestaties van query's. Hoewel automatische optimalisaties een aanzienlijke boost bieden, kunt u uw queryprestaties in sommige gevallen aanzienlijk 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 monitorlogboeken besproken. Zie Query best practices voor meer Azure Data Explorer optimalisatietips.

Geoptimaliseerde query's:

  • Versnel en verkort de totale duur van de uitvoering van de query.
  • De kans is kleiner dat deze wordt beperkt of geweigerd.

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. In deze scenario's kunt u overzichtsregels overwegen voor het maken en beheren van overzichtstabellen in uw Log Analytics-werkruimte. Samenvattingsregels nemen na een bepaalde vertraging samengevatte gegevens van grote gegevenssets opnieuw op, waardoor samenvattingstabellen worden gemaakt. Samenvattingstabellen worden efficiënter opgevraagd dan de oorspronkelijke onbewerkte gegevens.

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. Het deelvenster Querydetails bevat drie tabbladen:

  • Overzicht - Een gecureerde set prestatie-indicatoren
  • Onbewerkte statistieken - Alle gedetailleerde uitvoeringsstatistieken, werkruimten en query's waarnaar wordt verwezen, en andere technische gegevens
  • Fouten - Geeft een lijst weer van eventuele fouten die zijn opgetreden tijdens het uitvoeren van query's

Op dit tabblad Overzicht ziet u de resultaten van verschillende prestatie-indicatoren voor de query. Deze prestatie-indicatoren worden beschreven in de volgende sectie.

Schermafbeelding met het Query Details deelvenster in Azure Monitor Log Analytics.

Uitsplitsing van uitvoeringstijd van query

Bij het analyseren van queryprestaties in Azure Monitor Logs, biedt het deelvenster Querydetails een Uitvoeringstijd die de totale duur van de query van begin tot eind weerspiegelt. Deze statistiek is onderverdeeld in drie afzonderlijke onderdelen om prestatieknelpunten te identificeren:

  1. Engine Execution Time Dit is de tijd die nodig is om de query uit te voeren binnen de onderliggende gegevensengine, zoals Azure Data Explorer of andere onderdelen. Als deze waarde de primaire bijdrager is aan de totale uitvoeringstijd, kan dit erop wijzen dat de query zelf kan worden geoptimaliseerd. Raadpleeg de optimalisatietechnieken die in dit document worden beschreven om de prestaties te verbeteren.

  2. Serviceuitvoeringstijd Dit vertegenwoordigt de tijd die is besteed aan de Azure Monitor Logboeken-service zelf, buiten de gegevensengine. Het omvat interne verwerking en orkestratie.

  3. Servicewachtrijtijd Dit is de tijd die de query heeft besteed aan het wachten in de wachtrij van de Azure Monitor Logs-service voordat deze wordt uitgevoerd. Als deze waarde is ingevuld (bijvoorbeeld niet de standaardwaarde van N/B), geeft dit aan dat de gebruiker gelijktijdigheidslimieten heeft bereikt vanwege meerdere gelijktijdige query's. Een hoge wachtrijtijd geeft aan dat andere gelijktijdige query's resource-intensief kunnen zijn en moeten worden gecontroleerd en geoptimaliseerd om conflicten te verminderen. Zie limieten van Azure Monitor-service - Azure Monitor | Microsoft Learn. Azure Servicelimieten bewaken : beperking van gebruikersquery's

Prestatie-indicatoren voor queries

Elke query die u uitvoert, bevat de volgende prestatie-indicatoren voor query's:

  • 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.
  • Tijdsduur van de verwerkte query: de kloof tussen de nieuwste en de oudste gegevens waartoe de query toegang heeft. Het expliciete tijdsbereik dat u opgeeft voor de query is van invloed op deze indicator.
  • Leeftijd van verwerkte gegevens: de kloof tussen nu en de oudste gegevens waartoe de query toegang heeft. Deze indicator heeft een hoge invloed op de efficiëntie van het ophalen van gegevens.
  • Aantal werkruimten: hoeveel werkruimten de query heeft geopend tijdens het verwerken van query's op basis van impliciete of expliciete selectie.
  • Aantal regio's: hoeveel regio's de query heeft geopend tijdens het verwerken van query's 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: hoeveel het systeem de query heeft uitgevoerd op meerdere knooppunten. Deze indicator is alleen relevant voor query's met een hoog CPU-verbruik. Het gebruik van specifieke functies en operators heeft invloed op deze indicator.
  • Piek in het geheugen: de maximale hoeveelheid geheugen die door het systeem wordt gebruikt tijdens het uitvoeren van deze query. Deze waarde omvat geheugen dat wordt verbruikt door het laden, verwerken en tijdelijk storage tijdens de uitvoering.

Totale CPU

Deze metrische waarde toont de werkelijke reken-CPU die de query verwerkt op alle knooppunten voor queryverwerking. 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.

Als een query meer dan 100 seconden CPU gebruikt, verbruikt deze overmatige resources. Als een query meer dan 1000 seconden CPU gebruikt, wordt deze beschouwd als een beledigende query en kan deze 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 knooppunten voor het verwerken van query’s, gebruikt Azure Monitor Logs tijd aan:

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

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

Vroege filtering van records voordat hoge CPU-functies worden gebruikt

Sommige queryopdrachten en -functies maken gebruik van een hoog CPU-gebruik. 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 . Door deze voorwaarden toe te voegen, kunt u 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 where-componenten bevatten voor een geëvalueerde kolom in plaats van op kolommen die fysiek aanwezig zijn in de gegevensset, verliezen de 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 maakt de query-verwerkingsengine impliciet de geëvalueerde kolom aan omdat de filtering niet alleen op het veld plaatsvindt.

//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 nauwe schatting te maken van een afzonderlijk aantal grote gegevenssets zonder dat elke waarde daadwerkelijk wordt geteld.

De percentielfuncties doen vergelijkbare benaderingen met behulp van het dichtstbijzijnde rang 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.

Join en summarize opdrachten kunnen een hoog CPU-gebruik veroorzaken 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 altijd één-op-één gekoppeld is aan CounterName en ObjectName. De tweede query 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 equal == en startswith, hebben ongeveer dezelfde CPU-impact. Geavanceerde tekstovereenkomsten hebben meer invloed. De operator has is 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. In veel gevallen is het eenvoudiger om ze als tekenreeksen te parseren wanneer u slechts één of twee parameters nodig hebt en de XML- of JSON-objecten eenvoudig zijn. Gebruik de operator parse of andere textparseertechnieken. De prestatieverhoging is belangrijker naarmate 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

Grote parseringsopdrachten opsplitsen

Wanneer u de parse operator gebruikt, kunt u maximaal vijf kolommen extraheren in één instructie. Een overmatig aantal extracties in één instructie kan leiden tot een aanzienlijk hogere verwerkingstijd. Breek de extracties in plaats daarvan op in meerdere parse instructies.

Notitie

In transformaties is de parse operator beperkt tot 10 extracties in één instructie.

De volgende query's produceren bijvoorbeeld dezelfde resultaten, maar de tweede is aanzienlijk efficiënter omdat de parseringsbewerking in meerdere kleinere opdrachten wordt verbroken.

//less efficient
LogData
| parse Message with
   * "field1=" Field1: string
   " field2=" Field2: string
   " field3=" Field3: string
   " field4=" Field4: string
   " field5=" Field5: string
   " field6=" Field6: string
   " field7=" Field7: string
   " field8=" Field8: string
   " field9=" Field9: string
   " field10=" Field10: string *
//more efficient
LogData
| parse Message with
   * "field1=" Field1: string
   " field2=" Field2: string
   " field3=" Field3: string
   " field4=" Field4: string
   " field5=" Field5: string *
| parse Message with
   * " field6=" Field6: string
   " field7=" Field7: string
   " field8=" Field8: string
   " field9=" Field9: string
   " field10=" Field10: string *

Vermijd onnodig gebruik van zoek- en samenvoegoperators

Een factor die de verwerkte gegevens verhoogt, is het gebruik van veel tabellen. Dit scenario treedt meestal op wanneer u de search *- en union *-opdrachten gebruikt. Met deze opdrachten dwingt u af dat het systeem gegevens uit alle tabellen in de werkruimte evalueert en scant. In sommige gevallen bestaan er 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

U kunt het gegevensvolume verminderen door where voorwaarden vroeg in de query toe te voegen. Het Azure Data Explorer-platform bevat een cache waarmee wordt aangegeven welke partities gegevens bevatten die relevant zijn voor een specifieke voorwaarde where. 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

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

Gebruik voorwaardelijke aggregatiefuncties om dit prestatieprobleem te voorkomen. De meeste functies van aggregatie die u in een samenvattingsoperator gebruikt, hebben een voorwaardelijke versie. Gebruik de voorwaardelijke versie om één samenvattingsoperator met meerdere voorwaarden op te halen.

In de volgende query's ziet u bijvoorbeeld het aantal aanmeldingsgebeurtenissen en het aantal procesuitvoeringsgebeurtenissen 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 parse operator 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 het aanwijzen van 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 elke instantie.

Het aantal opgehaalde kolommen verminderen

Omdat Azure Data Explorer een kolomgegevensarchief is, is het ophalen van elke kolom onafhankelijk van de andere. Het aantal opgehaalde kolommen heeft rechtstreeks invloed op het totale gegevensvolume. Neem alleen de kolommen op in de uitvoer die u nodig hebt door de resultaten samen te vatten of door 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 samenvatting, 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 Logs worden gepartitioneerd volgens de kolom TimeGenerated. Het aantal partities waartoe de query toegang heeft, is rechtstreeks gerelateerd aan de periode. Het verkorten van de tijdspanne is de meest efficiënte manier om een snelle query-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 Logquerybereik en tijdsbereik 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 voorwaarde op TimeGenerated in de query op te nemen. Gebruik deze methode omdat de tijdspanne is vastgesteld, ook al wordt de query 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 voorwaarde where 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. Voorbeeld:

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 union over verschillende tabellen. Wanneer u de samenvoeging uitvoert, moet elke subquery binnen het bereik vallen. U kunt een instructie [let]'(/azure/kusto/query/letstatement) 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 zeven 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 de query alle relevante records scant, scant het systeem de hele partitie. Dit proces kan enkele uren en zelfs meer dan een dag omvatten.

In verschillende gevallen kan het systeem geen nauwkeurige meting van de tijdspanne leveren. 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 storage lagen: 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 de 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 sommige query's maken per ongeluk gebruik van oude gegevens. 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 zijn opgeslagen in de tabel. Wanneer de gegevensretentie lang is, kan dit lange tijdsbereiken omvatten. Als gevolg hiervan worden gegevens gescand die net zo oud zijn als de gegevensretentieperiode.

Voorbeelden van dergelijke gevallen zijn de volgende situaties:

  • 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 geen tijdsbereik forceert, 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. Voorbeeld:

  • U vermeldt expliciet verschillende werkruimten en ze bevinden zich in verschillende regio's.
  • Een resource-scoped query haalt data op en de data wordt 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 u niet al deze regio's hoeft te scannen, past u het bereik aan zodat het minder regio's omvat. Als u het resourcebereik minimaliseert, maar er nog steeds veel regio's worden gebruikt, kan onjuiste configuratie de oorzaak zijn. 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 u een query uitvoert in verschillende regio's, zijn de CPU- en gegevensmetingen niet nauwkeurig en vertegenwoordigen ze de meting van slechts één van de regio's.

Aantal werkruimten

Gebruik werkruimten als logische containers om logboekgegevens te scheiden en te beheren. De back-end optimaliseert de plaatsing van werkruimten op fysieke clusters binnen de geselecteerde regio.

Meerdere werkruimten zijn afkomstig uit deze situaties:

  • Verschillende werkruimten worden expliciet vermeld.
  • Een query gericht op resources haalt gegevens op die zijn 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, verbruikt overmatige resources. Queries 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, zoals een werkruimte-id of werkruimte Azure resource-id, verbruiken minder resources en presteren beter.

Zie Query over resources voor meer informatie.

Parallelisme

Azure Monitor Logs maakt 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, partitioneert het systeem de query en distribueert deze naar rekenknooppunten op basis van de gegevens die nodig zijn voor verwerking. In sommige situaties kan het systeem deze stap niet efficiënt uitvoeren, wat kan leiden tot een lange queryduur.

Querygedrag dat parallellisme kan verminderen, omvat:

  • In veel gevallen verlagen operators zoals join en summarize de algemene paralleliteit. Overweeg het gebruik van shuffle wanneer de prestaties problematisch zijn. Gebruik de shuffle query wanneer een sleutel (met andere woorden, een kolom die is samengevoegd of samengevat) veel unieke waarden (hoge cardinaliteit) heeft. Gebruik bijvoorbeeld willekeurige volgorde wanneer een kolom openbare IP-adressen bevat. Vermijd het gebruik van willekeurige volgorde voor sleutels met een lage kardinaliteit (zoals het ernstniveau van een gebeurtenis). Gebruik expliciet hint.shufflekey wanneer u meer dan één shuffle-query gebruikt om ervoor te zorgen dat elke sleutel van kracht wordt.
  • Gebruik van serialisatie- en vensterfuncties, zoals de serialize operator, next(), prev() en de row-functies. 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: range, sort, order, top, top-hitters en getschema.
  • Het gebruik van de aggregatiefunctie dcount() zorgt ervoor dat het systeem een centrale kopie van de afzonderlijke waarden heeft. 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 resourcebereikquery's kunnen op rollen gebaseerde Kubernetes-toegangscontrole (RBAC) of Azure RBAC-controles achterblijven in situaties waarin een groot aantal Azure-roltoewijzingen bestaan. 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 bestaan en elke resource veel roltoewijzingen op resourceniveau heeft, niet op 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.

Geheugenspiek

Geheugenpiek is de maximale hoeveelheid RAM die de Azure Data Explorer engine heeft waargenomen tijdens het uitvoeren van een query. Hierin wordt het geheugen behandeld dat wordt gebruikt voor het laden van gegevens (cache/dynamische leesbewerkingen), operatorverwerking (bijvoorbeeld join, summarize, make-series) en tijdelijke werksets. Het is een belangrijke indicator voor ongecontroleerde geheugencondities die beveiligingen activeren, zoals excessieve query's (E_RUNAWAY_QUERY, operator heeft het geheugenbudget overschreden) en E_LOW_MEMORY_CONDITION. Door de piek in het geheugen te bewaken, kunt u deze patronen vroeg ondervangen en query's afstemmen voordat ze gerelateerde harde limieten bereiken.

Hoe de geheugenpiek te verminderen

  • Volg dezelfde procedures als beschreven voor het totale CPU-gebruik. Pas voor elke tabel in de query met name vroeg filteren van records en projectie van kolommen toe.
  • In veel gevallen leiden operators zoals join en summarize tot een hoog geheugengebruik en kunnen leiden tot een runaway-query. Overweeg het gebruik van shuffle wanneer de prestaties problematisch zijn. Gebruik shuffle wanneer een sleutel (met andere woorden, een kolom waarmee is gekoppeld of samengevat) een hoge kardinaliteit heeft. Gebruik bijvoorbeeld willekeurige volgorde wanneer een kolom openbare IP-adressen bevat. Vermijd het gebruik van willekeurige volgorde voor sleutels met een lage kardinaliteit (zoals het ernstniveau van een gebeurtenis).
  • Als u join gebruikt, gebruikt u waar van toepassing best practices. Zie Query best practices.
  • Overweeg het gebruik van steekproeven.

Referentiedocumentatie voor de Kusto-querytaal