Azure Monitor에서 로그 쿼리 최적화Optimize log queries in Azure Monitor

Azure Monitor 로그는 ADX (Azure 데이터 탐색기) 를 사용 하 여 로그 데이터를 저장 하 고 쿼리를 실행 하 여 해당 데이터를 분석 합니다.Azure Monitor Logs uses Azure Data Explorer (ADX) to store log data and run queries for analyzing that data. ADX 클러스터를 만들고, 관리 하 고, 유지 관리 하며, 로그 분석 워크 로드에 맞게 최적화 합니다.It creates, manages, and maintains the ADX clusters for you, and optimizes them for your log analysis workload. 쿼리를 실행 하면 최적화 되 고 작업 영역 데이터를 저장 하는 적절 한 ADX 클러스터로 라우팅됩니다.When you run a query, it's optimized, and routed to the appropriate ADX cluster that stores the workspace data. Azure Monitor 로그와 Azure 데이터 탐색기 모두 자동 쿼리 최적화 메커니즘을 많이 사용 합니다.Both Azure Monitor Logs and Azure Data Explorer uses many automatic query optimization mechanisms. 자동 최적화는 상당한 향상을 제공 하지만 쿼리 성능을 크게 향상 시킬 수 있는 경우도 있습니다.While automatic optimizations provide significant boost, there are some cases where you can dramatically improve your query performance. 이 문서에서는 성능 고려 사항 및 해결을 위한 몇 가지 기법을 설명 합니다.This article explains the performance considerations and several techniques to fix them.

대부분의 기술은 여기에서 설명 하는 몇 가지 고유한 Azure Monitor 로그 고려 사항이 있지만 Azure 데이터 탐색기 및 Azure Monitor 로그에서 직접 실행 되는 쿼리에 공통적입니다.Most of the techniques are common to queries that are run directly on Azure Data Explorer and Azure Monitor Logs, though there are several unique Azure Monitor Logs considerations that are discussed here. Azure 데이터 탐색기 최적화 팁에 대 한 자세한 내용은 쿼리 모범 사례를 참조 하세요.For more Azure Data Explorer optimization tips, see Query best practices.

최적화 된 쿼리는 다음과 같습니다.Optimized queries will:

  • 더 빠르게 실행 하 여 쿼리 실행의 전체 지속 시간을 줄입니다.Run faster, reduce overall duration of the query execution.
  • 제한 되거나 거부 될 가능성이 더 적습니다.Have smaller chance of being throttled or rejected.

대시보드, 경고, Logic Apps, Power BI 등의 되풀이 및 버스 티 사용에 사용 되는 쿼리에 특히 주의 해야 합니다.You should give particular attention to queries that are used for recurrent and bursty usage such as dashboards, alerts, Logic Apps and Power BI. 이러한 경우에는 비효율적인 쿼리의 영향이 상당히 중요 합니다.The impact of an ineffective query in these cases is substantial.

쿼리 성능 창Query performance pane

Log Analytics에서 쿼리를 실행 한 후 쿼리 결과 위의 아래쪽 화살표를 클릭 하 여 쿼리에 대 한 여러 성능 표시기의 결과를 보여 주는 쿼리 성능 창을 확인 합니다.After you run a query in Log Analytics, click the down arrow above the query results to view the query performance pane that shows the results of several performance indicators for the query. 이러한 성능 표시기는 다음 섹션에 설명 되어 있습니다.These performance indicators are each described in the following section.

쿼리 성능 창

쿼리 성능 표시기Query performance indicators

다음 쿼리 성능 표시기는 실행 되는 모든 쿼리에 사용할 수 있습니다.The following query performance indicators are available for every query that is executed:

  • 총 CPU: 모든 계산 노드에서 쿼리를 처리 하는 데 사용 되는 전체 계산입니다.Total CPU: Overall compute used to process the query across all compute nodes. 계산, 구문 분석 및 데이터 페치에 사용 되는 시간을 나타냅니다.It represents time used for computing, parsing, and data fetching.

  • 처리 된 쿼리에 사용 되는 데이터: 쿼리를 처리 하기 위해 액세스 한 전체 데이터입니다.Data used for processed query: Overall data that was accessed to process the query. 대상 테이블 크기, 사용 된 시간 범위, 적용 된 필터 및 참조 되는 열 수의 영향을 받습니다.Influenced by the size of the target table, time span used, filters applied, and the number of columns referenced.

  • 처리 된 쿼리의 시간 범위: 쿼리를 처리 하기 위해 액세스 된 최신 데이터와 가장 오래 된 데이터 사이의 간격입니다.Time span of the processed query: The gap between the newest and the oldest data that was accessed to process the query. 쿼리에 대해 지정 된 명시적 시간 범위의 영향을 받습니다.Influenced by the explicit time range specified for the query.

  • 처리 된 데이터의 사용 기간: 현재와 쿼리를 처리 하기 위해 액세스 한 가장 오래 된 데이터 사이의 간격입니다.Age of processed data: The gap between now and the oldest data that was accessed to process the query. 데이터 인출의 효율성에 영향을 미칩니다.It highly influences the efficiency of data fetching.

  • 작업 영역 수: 암시적 또는 명시적 선택으로 인해 쿼리를 처리 하는 동안 액세스 된 작업 영역 수입니다.Number of workspaces: How many workspaces were accessed during the query processing due to implicit or explicit selection.

  • 지역 수: 작업 영역을 암시적으로 선택 하거나 명시적으로 선택 하 여 쿼리를 처리 하는 동안 액세스 된 영역 수입니다.Number of regions: How many regions were accessed during the query processing based due to implicit or explicit selection of workspaces. 다중 지역 쿼리는 훨씬 효율적이 고 성능 표시기는 부분 검사를 제공 합니다.Multi-region queries are much less efficient and performance indicators present partial coverage.

  • 병렬 처리: 여러 노드에서이 쿼리를 실행할 수 있었던 시스템 크기를 나타냅니다.Parallelism: Indicates how much the system was able to execute this query on multiple nodes. 높은 CPU 사용량이 있는 쿼리에만 해당 됩니다.Relevant only to queries that have high CPU consumption. 특정 함수 및 연산자를 사용 하 여 영향을 받습니다.Influenced by usage of specific functions and operators.

총 CPUTotal CPU

모든 쿼리 처리 노드에서이 쿼리를 처리 하는 데 투자 된 실제 계산 CPU입니다.The actual compute CPU that was invested to process this query across all the query processing nodes. 대부분의 쿼리는 많은 수의 노드에서 실행 되므로 일반적으로 쿼리를 실행 하는 데 걸린 기간 보다 훨씬 더 큽니다.Since most queries are executed on large numbers of nodes, this will usually be much larger than the duration the query actually took to execute.

100 초를 초과 하는 CPU를 활용 하는 쿼리는 과도 한 리소스를 사용 하는 쿼리로 간주 됩니다.Query that utilizes more than 100 seconds of CPU is considered a query that consumes excessive resources. 1000 초를 초과 하는 CPU를 활용 하는 쿼리는 악성 쿼리로 간주 되어 제한 될 수 있습니다.Query that utilizes more than 1,000 seconds of CPU is considered an abusive query and might be throttled.

쿼리 처리 시간은 다음에 소요 됩니다.Query processing time is spent on:

  • 데이터 검색 – 이전 데이터를 검색 하면 최근 데이터를 검색 하는 것 보다 시간이 더 많이 걸립니다.Data retrieval – retrieval of old data will consume more time than retrieval of recent data.
  • 데이터 처리 – 데이터의 논리 및 평가.Data processing – logic and evaluation of the data.

쿼리 처리 노드에 소요 된 시간 외에도, 사용자를 인증 하 고,이 데이터에 대 한 액세스를 허용 하는지 확인 하 고, 데이터 저장소를 찾고, 쿼리를 구문 분석 하 고, 쿼리 처리 노드를 할당 하는 데 사용 Azure Monitor 되는 추가 시간이 있습니다.Other than time spent in the query processing nodes, there is additional time that is spend by Azure Monitor Logs to: authenticate the user and verify that they are permitted to access this data, locate the data store, parse the query, and allocate the query processing nodes. 이 시간은 쿼리 총 CPU 시간에 포함 되지 않습니다.This time is not included in the query total CPU time.

높은 CPU 함수를 사용 하기 전에 레코드 조기 필터링Early filtering of records prior of using high CPU functions

일부 쿼리 명령 및 함수는 CPU 사용량이 크게 증가 합니다.Some of the query commands and functions are heavy in their CPU consumption. JSON 및 XML을 구문 분석 하거나 복잡 한 정규식을 추출 하는 명령의 경우 특히 그렇습니다.This is especially true for commands that parse JSON and XML or extract complex regular expressions. 이러한 구문 분석은 동적 열을 참조할 때 parse_json () 또는 parse_xml () 함수를 통해 명시적으로 또는 암시적으로 수행 될 수 있습니다.Such parsing can happen explicitly via parse_json() or parse_xml() functions or implicitly when referring to dynamic columns.

이러한 함수는 처리 하는 행 수에 비례하여 CPU를 사용 합니다.These functions consume CPU in proportion to the number of rows they are processing. 가장 효율적인 최적화는 CPU를 많이 사용 하는 함수를 실행 하기 전에 가능한 한 많은 레코드를 필터링 할 수 있는 where 조건을 쿼리 초기에 추가 하는 것입니다.The most efficient optimization is to add where conditions early in the query that can filter out as many records as possible before the CPU intensive function is executed.

예를 들어 다음 쿼리는 정확히 동일한 결과를 생성 하지만 두 번째 쿼리는 구문 분석 전의 where 조건에서 많은 레코드를 제외 하므로 가장 효율적입니다.For example, the following queries produce exactly the same result but the second one is by far the most efficient as the where condition before parsing excludes many records:

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

평가 된 where 절 사용 방지Avoid using evaluated where clauses

데이터 집합에 실제로 있는 열이 아닌 계산 된 열에 where 절이 포함 된 쿼리는 효율성을 잃게 됩니다.Queries that contain where clauses on an evaluated column rather than on columns that are physically present in the dataset lose efficiency. 계산 된 열에 대 한 필터링은 많은 양의 데이터 집합이 처리 될 때 일부 시스템 최적화를 방지 합니다.Filtering on evaluated columns prevents some system optimizations when large sets of data are handled. 예를 들어 다음 쿼리는 정확히 동일한 결과를 생성 하지만 두 번째 쿼리는 where 조건이 기본 제공 열을 참조 하는 것 보다 더 효율적입니다.For example, the following queries produce exactly the same result but the second one is more efficient as the where condition refers to built-in column

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

경우에 따라 필터링이 필드에만 수행 되는 것이 아니라 쿼리 처리 엔진에서 계산 된 열을 암시적으로 만듭니다.In some cases the evaluated column is created implicitly by the query processing engine since the filtering is done not just on the field:

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

요약 및 조인에서 효과적인 집계 명령 및 차원 사용Use effective aggregation commands and dimensions in summarize and join

Max (), sum (), count ()avg () 와 같은 일부 집계 명령은 논리로 인 한 CPU 영향은 낮지만, 다른 일부는 더 복잡 하며 효율적으로 실행 될 수 있도록 추론 및 추정치를 포함 합니다.While some aggregation commands like max(), sum(), count(), and avg() have low CPU impact due to their logic, other are more complex and include heuristics and estimations that allow them to be executed efficiently. 예를 들어 dcount () 는 HyperLogLog 알고리즘을 사용 하 여 각 값을 실제로 계산 하지 않고 대량 데이터 집합의 고유 개수에 대 한 종가를 제공 합니다. 백분위 수 함수는 가장 가까운 순위 백분위 수 알고리즘을 사용 하 여 유사한 근사치를 수행 합니다.For example, dcount() uses the HyperLogLog algorithm to provide close estimation to distinct count of large sets of data without actually counting each value; the percentile functions are doing similar approximations using the nearest rank percentile algorithm. 몇 가지 명령에는 영향을 줄이기 위한 선택적 매개 변수가 있습니다.Several of the commands include optional parameters to reduce their impact. 예를 들어 makeset () 함수에는 CPU 및 메모리에 크게 영향을 주는 최대 집합 크기를 정의 하는 선택적 매개 변수가 있습니다.For example, the makeset() function has an optional parameter to define the maximum set size, which significantly affects the CPU and memory.

조인요약 명령을 사용 하면 큰 데이터 집합을 처리할 때 CPU 사용률이 높아질 수 있습니다.Join and summarize commands may cause high CPU utilization when they are processing a large set of data. 복잡성은 cardinality by 요약 또는 조인 특성으로를 사용 하는 열의 가능한 값 (카디널리티 라고 함)의 수와 직접적으로 관련이 있습니다.Their complexity is directly related to the number of possible values, referred to as cardinality, of the columns that are using as the by in summarize or as the join attributes. 조인 및 요약의 설명 및 최적화에 대 한 자세한 내용은 해당 설명서 문서 및 최적화 팁을 참조 하세요.For explanation and optimization of join and summarize, see their documentation articles and optimization tips.

예를 들어, Counterpath 는 항상 CounterNameObjectName 에 매핑되어야 하므로 다음 쿼리는 정확히 동일한 결과를 생성 합니다.For example, the following queries produce exactly the same result because CounterPath is always one-to-one mapped to CounterName and ObjectName. 두 번째 방법은 집계 차원이 더 작기 때문에 더 효율적입니다.The second one is more efficient as the aggregation dimension is smaller:

//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 소비는 집약적 컴퓨팅이 필요한 조건 또는 확장 된 열의 경우에도 영향을 받을 수 있습니다.CPU consumption might also be impacted by where conditions or extended columns that require intensive computing. Equal = =startswith 와 같은 모든 trivial 문자열 비교는 고급 텍스트 일치에 더 많은 영향을 주는 반면 CPU 영향은 거의 동일 합니다.All trivial string comparisons such as equal == and startswith have roughly the same CPU impact while advanced text matches have more impact. 특히 contains 연산자 contains 연산자 보다 더 효율적입니다.Specifically, the has operator is more efficient that the contains operator. 문자열 처리 기법 때문에 짧은 문자열 보다 4 자 보다 긴 문자열을 찾는 것이 더 효율적입니다.Due to string handling techniques, it is more efficient to look for strings that are longer than four characters than short strings.

예를 들어 다음 쿼리는 컴퓨터 명명 정책에 따라 유사한 결과를 생성 하지만 두 번째 쿼리는 더 효율적입니다.For example, the following queries produce similar results, depending on Computer naming policy, but the second one is more efficient:

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

참고

이 지표는 즉각적인 클러스터의 CPU만 제공 합니다.This indicator presents only CPU from the immediate cluster. 다중 지역 쿼리에서는 지역 중 하나만 표시 합니다.In multi-region query, it would represent only one of the regions. 다중 작업 영역 쿼리에서는 일부 작업 영역을 포함 하지 않을 수 있습니다.In multi-workspace query, it might not include all workspaces.

문자열 구문 분석이 작동할 때 전체 XML 및 JSON 구문 분석 방지Avoid full XML and JSON parsing when string parsing works

XML 또는 JSON 개체의 전체 구문 분석에는 높은 CPU 및 메모리 리소스가 사용 될 수 있습니다.Full parsing of an XML or JSON object may consume high CPU and memory resources. 대부분의 경우에는 매개 변수를 한 개 또는 두 개만 사용 하 고 XML 또는 JSON 개체를 간단 하 게 사용 하는 경우 구문 분석 연산자나 기타 텍스트 구문 분석 기법을 사용 하 여 문자열로 구문 분석 하는 것이 더 쉽습니다.In many cases, when only one or two parameters are needed and the XML or JSON objects are simple, it is easier to parse them as strings using the parse operator or other text parsing techniques. XML 또는 JSON 개체의 레코드 수가 증가할수록 성능 향상이 더 중요 합니다.The performance boost will be more significant as the number of records in the XML or JSON object increases. 레코드 수가 수십 억 개에 도달 하는 경우 반드시 필요 합니다.It is essential when the number of records reaches tens of millions.

예를 들어 다음 쿼리는 전체 XML 구문 분석을 수행 하지 않고 위의 쿼리와 정확히 동일한 결과를 반환 합니다.For example, the following query will return exactly the same results as the queries above without performing full XML parsing. 이 파일은 FileHash 뒤에 오는 파일 경로와 같은 XML 파일 구조에 대해 몇 가지 가정을 하 고 특성을 포함 하지 않습니다.Note that it makes some assumptions on the XML file structure such as that FilePath element comes after FileHash and none of them has attributes.

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

처리 된 쿼리에 사용 되는 데이터Data used for processed query

쿼리를 처리 하는 데 중요 한 요소는 검색 되어 쿼리 처리에 사용 되는 데이터의 양입니다.A critical factor in the processing of the query is the volume of data that is scanned and used for the query processing. Azure 데이터 탐색기는 다른 데이터 플랫폼과 비교 하 여 데이터 볼륨을 크게 줄이는 적극적인 최적화를 사용 합니다.Azure Data Explorer uses aggressive optimizations that dramatically reduce the data volume compared to other data platforms. 쿼리에는 사용 되는 데이터 볼륨에 영향을 줄 수 있는 중요 한 요인이 있습니다.Still, there are critical factors in the query that can impact the data volume that is used.

2 개 이상의 데이터를 처리 하는 쿼리는 과도 한 리소스를 사용 하는 쿼리로 간주 됩니다.Query that processes more than 2,000KB of data is considered a query that consumes excessive resources. 20 개가 넘는 데이터를 처리 하는 쿼리는 악성 쿼리로 간주 되어 제한 될 수 있습니다.Query that is processing more than 20,000KB of data is considered an abusive query and might be throttled.

Azure Monitor 로그에서 Timegenerated 열은 데이터를 인덱싱하는 방법으로 사용 됩니다.In Azure Monitor Logs, the TimeGenerated column is used as a way to index the data. Timegenerated 값을 가능한 한 범위를 좁히기 때문에 처리 해야 하는 데이터의 양을 크게 제한 하 여 쿼리 성능이 크게 향상 됩니다.Restricting the TimeGenerated values to as narrow a range as possible will make a significant improvement to query performance by significantly limiting the amount of data that has to be processed.

불필요 한 search 및 union 연산자 사용 방지Avoid unnecessary use of search and union operators

처리 중인 데이터를 늘리는 또 다른 요인은 많은 테이블을 사용 하는 것입니다.Another factor that increases the data that is process is the use of large number of tables. 이는 일반적으로 search *union * 명령을 사용 하는 경우에 발생 합니다.This usually happens when search * and union * commands are used. 이러한 명령을 통해 시스템은 작업 영역에 있는 모든 테이블의 데이터를 평가 하 고 검색 합니다.These commands force the system to evaluate and scan data from all tables in the workspace. 경우에 따라 작업 영역에 수백 개의 테이블이 있을 수 있습니다.In some cases, there might be hundreds of tables in the workspace. "검색 *" 또는 특정 테이블에 대 한 범위를 지정 하지 않고 검색을 사용 하 여 가능한 한 많이 방지 해 보세요.Try to avoid as much as possible using "search *" or any search without scoping it to a specific table.

예를 들어 다음 쿼리는 정확히 동일한 결과를 생성 하지만 마지막 쿼리는 가장 효율적입니다.For example, the following queries produce exactly the same result but the last one is by far the most efficient:

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

쿼리에 초기 필터 추가Add early filters to the query

데이터 볼륨을 줄이는 또 다른 방법은 쿼리의 초기에 조건을 포함 하는 것입니다 .Another method to reduce the data volume is to have where conditions early in the query. Azure 데이터 탐색기 플랫폼은 특정 where 조건과 관련 된 데이터를 포함 하는 파티션을 확인할 수 있도록 하는 캐시를 포함 합니다.The Azure Data Explorer platform includes a cache that lets it know which partitions include data that is relevant for a specific where condition. 예를 들어 쿼리에가 포함 된 경우 일치 하는 where EventID == 4624 이벤트를 포함 하는 파티션을 처리 하는 노드에만 쿼리를 배포 합니다.For example, if a query contains where EventID == 4624 then it would distribute the query only to nodes that handle partitions with matching events.

다음 예제 쿼리는 정확히 동일한 결과를 생성 하지만 두 번째 쿼리는 더 효율적입니다.The following example queries produce exactly the same result but the second one is more efficient:

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

조건부 집계 함수 및 구체화 함수를 사용 하 여 동일한 원본 데이터의 여러 검색 방지Avoid multiple scans of same source data using conditional aggregation functions and materialize function

쿼리에 join 또는 union 연산자를 사용 하 여 병합 된 하위 쿼리가 여러 개 있는 경우 각 하위 쿼리는 전체 원본을 개별적으로 검색 한 다음 결과를 병합 합니다.When a query has several sub-queries that are merged using join or union operators, each sub-query scans the entire source separately and then merge the results. 매우 큰 데이터 집합에서 데이터를 검사 하는 데 중요 한 요소 수를 곱한 값입니다.This multiples the number of times data is scanned - critical factor in very large data sets.

이를 방지 하는 방법은 조건부 집계 함수를 사용 하는 것입니다.A technique to avoid this is by using the conditional aggregation functions. 요약 연산자에 사용 되는 대부분의 집계 함수 에는 여러 조건에서 단일 요약 연산자를 사용할 수 있도록 하는 조건 화 된 버전이 있습니다.Most of the aggregation functions that are used in summary operator has a conditioned version that allow you to use a single summarize operator with multiple conditions.

예를 들어 다음 쿼리는 로그인 이벤트의 수와 각 계정에 대 한 프로세스 실행 이벤트의 수를 보여 줍니다.For example, the following queries show the number of login events and the number of process execution events for each account. 동일한 결과를 반환 하지만 첫 번째는 데이터를 두 번 검색 하 고 두 번째는 한 번만 검색 하는 것입니다.They return the same results but the first is scanning the data twice, the second scan it only once:

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

하위 쿼리를 불필요 하 게 사용 하는 또 다른 경우는 특정 패턴과 일치 하는 레코드만 처리 되도록 구문 분석 연산자 를 미리 필터링 합니다.Another case where sub-queries are unnecessary is pre-filtering for parse operator to make sure that it processes only records that match specific pattern. 이는 구문 분석 연산자와 기타 유사한 연산자가 패턴이 일치 하지 않는 경우 빈 결과를 반환 하기 때문에 필요 하지 않습니다.This is unnecessary as the parse operator and other similar operators return empty results when the pattern doesn't match. 다음은 두 번째 쿼리가 데이터를 한 번만 검색 하는 동안 정확히 동일한 결과를 반환 하는 두 개의 쿼리입니다.Here are two queries that return exactly the same results while the second query scan data only once. 두 번째 쿼리에서는 각 구문 분석 명령만 해당 이벤트와 관련이 있습니다.In the second query, each parse command is relevant only for its events. 확장 연산자는 이후에 빈 데이터 상황을 참조 하는 방법을 보여 줍니다.The extend operator afterwards shows how to refer to empty data situation.

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

위에서 하위 쿼리를 사용 하지 않도록 하는 것이 허용 되지 않는 경우 다른 방법은 구체화 () 함수를 사용 하 여 각각의 원본 데이터를 사용 하는 쿼리 엔진에 대 한 힌트입니다.When the above doesn't allow to avoid using sub-queries, another technique is to hint to the query engine that there is a single source data used in each one of them using the materialize() function. 이는 쿼리 내에서 여러 번 사용 되는 함수에서 원본 데이터를 가져오는 경우에 유용 합니다.This is useful when the source data is coming from a function that is used several times within the query. 구체화는 하위 쿼리의 출력이 입력 보다 훨씬 작은 경우에 적용 됩니다.Materialize is effective when the output of the sub-query is much smaller than the input. 쿼리 엔진은 모든 항목에서 출력을 캐시 하 고 다시 사용 합니다.The query engine will cache and reuse the output in all occurrences.

검색 되는 열 수 줄이기Reduce the number of columns that is retrieved

Azure 데이터 탐색기은 칼럼 형식 데이터 저장소 이므로 모든 열을 검색 하는 것은 다른 열과는 별개입니다.Since Azure Data Explorer is a columnar data store, retrieval of every column is independent of the others. 검색 되는 열 수는 전체 데이터 볼륨에 직접 영향을 미칩니다.The number of columns that are retrieved directly influences the overall data volume. 결과를 요약 하거나 특정 열을 프로젝션 하는 데 필요한 출력에만 열을 포함 해야 합니다.You should only include the columns in the output that are needed by summarizing the results or projecting the specific columns. Azure 데이터 탐색기에는 검색 된 열 수를 줄이기 위한 여러 최적화 기능이 있습니다.Azure Data Explorer has several optimizations to reduce the number of retrieved columns. 열이 필요 하지 않은 것으로 확인 된 경우 (예: 요약 명령에서 참조 하지 않는 경우) 검색 하지 않습니다.If it determines that a column isn't needed, for example if it's not referenced in the summarize command, it won't retrieve it.

예를 들어 두 번째 쿼리는 한 열이 아니라 세 개의 열을 인출 해야 하므로 세 배 더 많은 데이터를 처리할 수 있습니다.For example, the second query may process three times more data since it needs to fetch not one column but three:

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

처리 된 쿼리의 시간 범위Time span of the processed query

Azure Monitor 로그의 모든 로그는 Timegenerated 열에 따라 분할 됩니다.All logs in Azure Monitor Logs are partitioned according to the TimeGenerated column. 액세스 되는 파티션 수는 시간 범위와 직접적으로 관련이 있습니다.The number of partitions that are accessed are directly related to the time span. 시간 범위를 줄이는 것은 프롬프트 쿼리 실행을 보장 하는 가장 효율적인 방법입니다.Reducing the time range is the most efficient way of assuring a prompt query execution.

시간 범위가 15 일을 초과 하는 쿼리는 과도 한 리소스를 사용 하는 쿼리로 간주 됩니다.Query with time span of more than 15 days is considered a query that consumes excessive resources. 시간 범위가 90 일을 초과 하는 쿼리는 악성 쿼리로 간주 되어 제한 될 수 있습니다.Query with time span of more than 90 days is considered an abusive query and might be throttled.

시간 범위는 Azure Monitor Log Analytics의 로그 쿼리 범위 및 시간 범위에 설명 된 대로 Log Analytics 화면의 시간 범위 선택기를 사용 하 여 설정할 수 있습니다.The time range can be set using the time range selector in the Log Analytics screen as described in Log query scope and time range in Azure Monitor Log Analytics. 선택한 시간 범위는 쿼리 메타 데이터를 사용 하 여 백 엔드로 전달 되기 때문에 권장 되는 방법입니다.This is the recommended method as the selected time range is passed to the backend using the query metadata.

또 다른 방법은 Timegenerated 에서 쿼리에서 생성 된 where 조건을 명시적으로 포함 하는 것입니다.An alternative method is to explicitly include a where condition on TimeGenerated in the query. 쿼리가 다른 인터페이스에서 사용 되는 경우에도 시간 범위가 고정 되도록 하려면이 메서드를 사용 해야 합니다.You should use this method as it assures that the time span is fixed, even when the query is used from a different interface. 쿼리의 모든 부분에 Timegenerated 필터가 있는지 확인 해야 합니다.You should ensure that all parts of the query have TimeGenerated filters. 쿼리가 여러 테이블 또는 동일한 테이블에서 데이터를 인출 하는 하위 쿼리를 포함 하는 경우 각각에 고유한 where 조건을 포함 해야 합니다.When a query has sub-queries fetching data from various tables or the same table, each has to include its own where condition.

모든 하위 쿼리가 TimeGenerated 필터를 사용 하는지 확인Make sure all sub-queries have TimeGenerated filter

예를 들어 다음 쿼리에서는 성능 테이블이 마지막 일 동안만 검색 되는 반면, 하트 비트 테이블은 최대 2 년이 될 수 있습니다.For example, in the following query, while the Perf table will be scanned only for the last day, the Heartbeat table will be scanned for all of its history, which might be up to two years:

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

이러한 실수가 발생 하는 일반적인 경우는 arg_max () 를 사용 하 여 가장 최근에 발생 한 항목을 찾는 경우입니다.A common case where such a mistake occurs is when arg_max() is used to find the most recent occurrence. 예:For example:

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

이는 내부 쿼리에서 시간 필터를 추가 하 여 쉽게 수정할 수 있습니다.This can be easily corrected by adding a time filter in the inner 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

이 오류에 대 한 또 다른 예는 여러 테이블에 대 한 공용 구조체 바로 다음 시간 범위 필터링을 수행 하는 경우입니다.Another example for this fault is when performing the time scope filtering just after a union over several tables. Union을 수행할 때 각 하위 쿼리는 범위를 지정 해야 합니다.When performing the union, each sub-query should be scoped. Let 문을 사용 하 여 범위 일관성을 보장할 수 있습니다.You can use let statement to assure scoping consistency.

예를 들어 다음 쿼리는 지난 1 일 뿐만 아니라 하트 비트Perf 테이블의 모든 데이터를 검색 합니다.For example, the following query will scan all the data in the Heartbeat and Perf tables, not just the last 1 day:

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

이 쿼리는 다음과 같이 수정 해야 합니다.This query should be fixed as follows:

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

시간 범위 측정 제한Time span measurement limitations

측정은 항상 지정 된 실제 시간 보다 큽니다.The measurement is always larger than the actual time specified. 예를 들어, 쿼리에 대 한 필터가 7 일 이면 시스템은 7.5 또는 8.1 일을 검사할 수 있습니다.For example, if the filter on the query is 7 days, the system might scan 7.5 or 8.1 days. 이는 시스템에서 데이터를 가변 크기의 청크로 분할 하기 때문입니다.This is because the system is partitioning the data into chunks in variable size. 모든 관련 레코드가 검색 되도록 하기 위해 여러 시간 및 하루 이상 처리할 수 있는 전체 파티션을 검색 합니다.To assure that all relevant records are scanned, it scans the entire partition that might cover several hours and even more than a day.

시스템에서 시간 범위에 대 한 정확한 측정을 제공할 수 없는 여러 가지 경우가 있습니다.There are several cases where the system cannot provide an accurate measurement of the time range. 이는 쿼리의 범위가 하루 이하인 경우 또는 다중 작업 영역 쿼리에서 발생 합니다.This happens in most of the cases where the query's span less than a day or in multi-workspace queries.

중요

이 지표는 즉각적인 클러스터에서 처리 된 데이터만 표시 합니다.This indicator presents only data processed in the immediate cluster. 다중 지역 쿼리에서는 지역 중 하나만 표시 합니다.In multi-region query, it would represent only one of the regions. 다중 작업 영역 쿼리에서는 일부 작업 영역을 포함 하지 않을 수 있습니다.In multi-workspace query, it might not include all workspaces.

처리 된 데이터의 보존 기간Age of processed data

Azure 데이터 탐색기는 메모리 내, 로컬 SSD 디스크 및 훨씬 느린 Azure Blob의 여러 저장소 계층을 사용 합니다.Azure Data Explorer uses several storage tiers: in-memory, local SSD disks and much slower Azure Blobs. 최신 데이터는 더 높은 데이터를 더 높은 성능의 계층에 저장 하 여 쿼리 지속 시간 및 CPU를 줄일 수 있습니다.The newer the data, the higher is the chance that it is stored in a more performant tier with smaller latency, reducing the query duration and CPU. 데이터 자체 외에도 시스템은 메타 데이터에 대 한 캐시를 포함 합니다.Other than the data itself, the system also has a cache for metadata. 데이터의 오래 된 데이터는 캐시에 있는 메타 데이터의 확률을 줄일 수 있습니다.The older the data, the less chance its metadata will be in cache.

14 일 보다 오래 된 데이터를 처리 하는 쿼리는 과도 한 리소스를 소비 하는 쿼리로 간주 됩니다.Query that processes data than is more than 14 days old is considered a query that consumes excessive resources.

일부 쿼리에서는 오래 된 데이터를 사용 해야 하지만 오래 된 데이터가 실수로 사용 되는 경우가 있습니다.While some queries require usage of old data, there are cases where old data is used by mistake. 이는 메타 데이터의 시간 범위를 제공 하지 않고 쿼리를 실행 하 고 모든 테이블 참조에 Timegenerated 열에 대 한 필터를 포함 하지 않는 경우에 발생 합니다.This happens when queries are executed without providing time range in their meta-data and not all table references include filter on the TimeGenerated column. 이 경우 시스템은 해당 테이블에 저장 된 모든 데이터를 검색 합니다.In these cases, the system will scan all the data that is stored in that table. 데이터 보존이 길면 긴 시간 범위를 포함할 수 있으므로 데이터 보존 기간으로 오래 된 데이터입니다.When the data retention is long, it can cover long time ranges and thus data that is as old as the data retention period.

예를 들면 다음과 같습니다.Such cases can be for example:

  • 제한 되지 않는 하위 쿼리를 사용 하 여 Log Analytics 시간 범위를 설정 하지 않습니다.Not setting the time range in Log Analytics with a sub-query that isn't limited. 위 예제를 참조하세요.See example above.
  • 시간 범위 옵션 매개 변수 없이 API를 사용 합니다.Using the API without the time range optional parameters.
  • Power BI 커넥터와 같은 시간 범위를 적용 하지 않는 클라이언트를 사용 합니다.Using a client that doesn't force a time range such as the Power BI connector.

이 경우에도 관련이 있으므로 이전 섹션의 예제 및 메모를 참조 하세요.See examples and notes in the pervious section as they are also relevant in this case.

영역 수Number of regions

여러 지역에서 단일 쿼리가 실행 될 수 있는 여러 가지 상황이 있습니다.There are several situations where a single query might be executed across different regions:

  • 여러 작업 영역이 명시적으로 나열 되 고 서로 다른 지역에 있습니다.When several workspaces are explicitly listed, and they are located in different regions.
  • 리소스 범위 쿼리가 데이터를 인출 하 고 데이터가 다른 지역에 있는 여러 작업 영역에 저장 되어 있는 경우When a resource-scoped query is fetching data and the data is stored in multiple workspaces that are located in different regions.

영역 간 쿼리를 실행 하려면 시스템에서 일반적으로 쿼리 최종 결과 보다 훨씬 큰 백 엔드 대량의 중간 데이터를 직렬화 하 고 전송 해야 합니다.Cross-region query execution requires the system to serialize and transfer in the backend large chunks of intermediate data that are usually much larger than the query final results. 또한 최적화, 추론 및 캐시 활용을 수행 하는 시스템의 기능을 제한 합니다.It also limits the system's ability to perform optimizations, heuristics, and utilize caches. 이러한 지역을 모두 검색할 수 있는 실질적인 이유가 없으면 범위를 조정 하 여 더 작은 영역을 포함 하도록 해야 합니다.If there is no real reason to scan all these regions, you should adjust the scope so it covers fewer regions. 리소스 범위를 최소화 하지만 여전히 많은 지역을 사용 하는 경우 잘못 된 구성으로 인해 발생할 수 있습니다.If the resource scope is minimized but still many regions are used, it might happen due to misconfiguration. 예를 들어 감사 로그 및 진단 설정이 다른 지역의 다른 작업 영역으로 전송 되거나 여러 진단 설정 구성이 있습니다.For example, audit logs and diagnostic settings are sent to different workspaces in different regions or there are multiple diagnostic settings configurations.

3 개 이상의 지역에 걸쳐 있는 쿼리는 과도 한 리소스를 사용 하는 쿼리로 간주 됩니다.Query that spans more than 3 regions is considered a query that consumes excessive resources. 6 개 이상의 지역에 걸친 쿼리는 악성 쿼리로 간주 되어 제한 될 수 있습니다.Query that spans more than 6 regions is considered an abusive query and might be throttled.

중요

쿼리가 여러 지역에서 실행 되는 경우 CPU 및 데이터 측정이 정확 하지 않으며 지역 중 하나에만 해당 하는 측정값을 나타냅니다.When a query is run across several regions, the CPU and data measurements will not be accurate and will represent the measurement only on one of the regions.

작업 영역 수Number of workspaces

작업 영역은 로그 데이터를 분리 하 고 관리 하는 데 사용 되는 논리적 컨테이너입니다.Workspaces are logical containers that are used to segregate and administer logs data. 백 엔드는 선택한 지역 내에서 실제 클러스터의 작업 영역 배치를 최적화 합니다.The backend optimizes workspace placements on physical clusters within the selected region.

여러 작업 영역을 사용 하면 다음과 같은 결과가 발생할 수 있습니다.Usage of multiple workspaces can result from:

  • 여러 작업 영역이 명시적으로 나열 됩니다.Where several workspaces are explicitly listed.
  • 리소스 범위 쿼리가 데이터를 인출 하 고 데이터가 여러 작업 영역에 저장 되는 경우When a resource-scoped query is fetching data and the data is stored in multiple workspaces.

하위 지역 및 클러스터 간 쿼리를 실행 하려면 시스템에서 일반적으로 쿼리 최종 결과 보다 훨씬 큰 백 엔드 대량의 중간 데이터를 직렬화 하 고 전송 해야 합니다.Cross-region and cross-cluster execution of queries requires the system to serialize and transfer in the backend large chunks of intermediate data that are usually much larger than the query final results. 또한 최적화를 수행 하 고, 추론을 수행 하 고, 캐시를 활용 하는 시스템 기능을 제한 합니다.It also limits the system ability to perform optimizations, heuristics and utilizing caches.

5 개 이상의 작업 영역에 걸친 쿼리는 과도 한 리소스를 사용 하는 쿼리로 간주 됩니다.Query that spans more than 5 workspace is considered a query that consumes excessive resources. 쿼리가 100 개 이상의 작업 영역에 걸쳐 있을 수 없습니다.Queries cannot span to to more than 100 workspaces.

중요

일부 다중 작업 영역 시나리오에서 CPU 및 데이터 측정은 정확 하지 않으며 작업 영역 중 일부에만 해당 하는 측정값을 나타냅니다.In some multi-workspace scenarios, the CPU and data measurements will not be accurate and will represent the measurement only to few of the workspaces.

병렬 처리Parallelism

Azure Monitor 로그는 Azure 데이터 탐색기의 대규모 클러스터를 사용 하 여 쿼리를 실행 하 고, 이러한 클러스터는 규모에 따라 달라 지 며, 잠재적으로 수십 개의 계산 노드를 가져올 수 있습니다.Azure Monitor Logs is using large clusters of Azure Data Explorer to run queries, and these clusters vary in scale, potentially getting up to dozens of compute nodes. 시스템은 작업 영역 배치 논리 및 용량에 따라 클러스터 크기를 자동으로 조정 합니다.The system automatically scales the clusters according to workspace placement logic and capacity.

쿼리를 효율적으로 실행 하기 위해 데이터를 처리 하는 데 필요한 데이터를 기반으로 분할 하 고 계산 노드에 배포 합니다.To efficiently execute a query, it is partitioned and distributed to compute nodes based on the data that is required for its processing. 시스템에서이 작업을 효율적으로 수행할 수 없는 경우도 있습니다.There are some situations where the system cannot do this efficiently. 이로 인해 쿼리 시간이 길어질 수 있습니다.This can lead to a long duration of the query.

병렬 처리를 줄일 수 있는 쿼리 동작은 다음과 같습니다.Query behaviors that can reduce parallelism include:

  • 직렬화 연산자, next (), prev ()row 함수와 같은 직렬화 및 창 함수를 사용 합니다.Use of serialization and window functions such as the serialize operator, next(), prev(), and the row functions. 이러한 경우에는 시계열 및 사용자 분석 함수를 사용할 수 있습니다.Time series and user analytics functions can be used in some of these cases. 쿼리 끝에 범위, 정렬, 순서, 위쪽, hitters, getschema와 같은 연산자를 사용 하는 경우 비효율적인 serialization이 발생할 수도 있습니다.Inefficient serialization may also happen if the following operators are used not at the end of the query: range, sort, order, top, top-hitters, getschema.
  • Dcount () 집계 함수를 사용 하면 시스템에 고유 값의 중앙 복사본이 적용 됩니다.Usage of dcount() aggregation function force the system to have central copy of the distinct values. 데이터의 소수 자릿수가 높으면 dcount 함수 선택적인 매개 변수를 사용 하 여 정확도를 줄이는 것이 좋습니다.When the scale of data is high, consider using the dcount function optional parameters to reduced accuracy.
  • 대부분의 경우 조인 연산자는 전반적인 병렬 처리를 줄입니다.In many cases, the join operator lowers overall parallelism. 성능이 문제가 되는 경우 무작위 조인을 검사 합니다.Examine shuffle join as an alternative when performance is problematic.
  • 리소스 범위 쿼리에서는 많은 수의 Azure 역할 할당이 있는 경우 실행 전 Kubernetes RBAC 또는 Azure RBAC 검사가 지연 될 수 있습니다.In resource-scope queries, the pre-execution Kubernetes RBAC or Azure RBAC checks may linger in situations where there is very large number of Azure role assignments. 이로 인해 병렬 처리의 낮은 검사가 길어질 수 있습니다.This may lead to longer checks that would result in lower parallelism. 예를 들어 쿼리는 수천 개의 리소스가 있고 각 리소스는 구독 또는 리소스 그룹이 아니라 리소스 수준에서 많은 역할 할당을 보유 하는 구독에 대해 실행 됩니다.For example, a query is executed on a subscription where there are thousands of resources and each resource has many role assignments in the resource level, not on the subscription or resource group.
  • 쿼리가 작은 데이터 청크를 처리 하는 경우에는 시스템에서 여러 계산 노드에 분산 되지 않으므로 병렬 처리 속도가 낮습니다.If a query is processing small chunks of data, its parallelism will be low as the system will not spread it across many compute nodes.

다음 단계Next steps