

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# CloudTrail Lake 쿼리 최적화
<a name="lake-queries-optimization"></a>

이 페이지에서는 CloudTrail Lake 쿼리를 최적화하여 성능과 신뢰성을 개선하는 방법에 대한 지침을 제공합니다. 특정 최적화 기법과 일반적인 쿼리 실패에 대한 해결 방법을 다룹니다.

**Topics**
+ [쿼리 최적화를 위한 권장 사항](#lake-queries-tuning)
+ [쿼리 실패에 대한 해결 방법](#lake-queries-troubleshooting)

## 쿼리 최적화를 위한 권장 사항
<a name="lake-queries-tuning"></a>

이 섹션의 권장 사항에 따라 쿼리를 최적화합니다.

**Topics**
+ [집계 최적화](#query-optimization-aggregation)
+ [근사 기법 사용](#query-optimization-approximation)
+ [쿼리 결과 제한](#query-optimization-limit)
+ [LIKE 쿼리 최적화](#query-optimization-like)
+ [`UNION` 대신 `UNION ALL` 사용](#query-optimization-union)
+ [필수 열만 포함](#query-optimization-reqcolumns)
+ [창 함수 범위 축소](#query-optimization-windows)

### 집계 최적화
<a name="query-optimization-aggregation"></a>

`GROUP BY` 절에서 중복 열을 제외하면 더 적은 열에 메모리가 더 적게 필요하므로 성능이 향상될 수 있습니다. 예를 들어 다음 쿼리에서는 `eventType`과 같은 중복 열에서 `arbitrary` 함수를 사용하여 성능을 개선할 수 있습니다. `eventType`의 `arbitrary` 함수는 값이 동일하므로 그룹에서 필드 값을 무작위로 선택하는 데 사용되며 `GROUP BY` 절에는 포함할 필요가 없습니다.

```
SELECT eventName, eventSource, arbitrary(eventType), count(*) 
FROM $EDS_ID 
GROUP BY eventName, eventSource
```

`GROUP BY` 내 필드 목록을 고유한 값 수(카디널리티)의 내림차순으로 정렬하여 `GROUP BY` 함수의 성능을 개선할 수 있습니다. 예를 들어 각 유형의 이벤트 수를 가져오는 동안의 값`eventName`보다의 고유한 값이 더 많`awsRegion``eventName`기 때문에 대신 `GROUP BY` 함수의 `eventName` `awsRegion` 순서에 따라를 사용하여 AWS 리전성능을 개선할 수 있습니다`awsRegion`.

```
SELECT eventName, awsRegion, count(*) 
FROM $EDS_ID 
GROUP BY eventName, awsRegion
```

### 근사 기법 사용
<a name="query-optimization-approximation"></a>

고유 값을 계산하는 데 정확한 값이 필요하지 않은 경우 [근사 집계 함수](https://trino.io/docs/current/functions/aggregate.html#approximate-aggregate-functions)를 사용하여 가장 빈번한 값을 찾습니다. 예를 들어 [https://trino.io/docs/current/functions/aggregate.html#approx_distinct](https://trino.io/docs/current/functions/aggregate.html#approx_distinct)는 훨씬 적은 메모리를 사용하고 `COUNT(DISTINCT fieldName)` 작업보다 빠르게 실행됩니다.

### 쿼리 결과 제한
<a name="query-optimization-limit"></a>

쿼리에 샘플 응답만 필요한 경우 `LIMIT` 조건을 사용하여 결과를 소수의 행으로 제한합니다. 그렇게 하지 않으면 쿼리가 큰 결과를 반환하고 쿼리 실행에 더 많은 시간이 걸립니다.

`ORDER BY`와 함께 `LIMIT`를 사용하면 정렬에 필요한 메모리 양과 시간이 줄어들기 때문에 상단 또는 하단 N 레코드에 대한 결과를 더 빠르게 제공할 수 있습니다.

```
SELECT * FROM $EDS_ID
ORDER BY eventTime 
LIMIT 100;
```

### LIKE 쿼리 최적화
<a name="query-optimization-like"></a>

`LIKE`를 사용하여 일치하는 문자열을 찾을 수 있지만 문자열이 길면 컴퓨팅 용량을 많이 소비합니다. 이 [https://trino.io/docs/current/functions/regexp.html#regexp_like](https://trino.io/docs/current/functions/regexp.html#regexp_like) 함수는 대부분의 경우 더 빠른 대안입니다.

찾고 있는 하위 문자열을 고정하여 검색을 최적화할 수도 있습니다. 예를 들어 접두사를 찾고 있다면 `LIKE` 연산자에 '%`substr`%' 대신 '`substr`%'를 사용하고 `regexp_like` 함수에 '^`substr`'를 사용하는 것이 좋습니다.

### `UNION` 대신 `UNION ALL` 사용
<a name="query-optimization-union"></a>

`UNION ALL` 및 `UNION`은 두 쿼리의 결과를 하나의 결과로 결합하는 두 가지 방법이지만 `UNION`에서 중복된 항목을 제거합니다. `UNION`에서는 모든 레코드를 처리하고 중복을 찾아야 하므로 메모리와 컴퓨팅 용량을 많이 소비하지만 `UNION ALL`에서는 비교적 속도가 빠른 연산입니다. 레코드의 중복을 제거해야 하는 경우가 아니라면 최상의 성능을 위해 `UNION ALL`을 사용합니다.

### 필수 열만 포함
<a name="query-optimization-reqcolumns"></a>

열이 필요하지 않은 경우 쿼리에 포함하지 않습니다. 쿼리에서 처리해야 하는 데이터가 적을수록 실행 속도가 빨라집니다. 가장 바깥쪽 쿼리에서 `SELECT *`를 수행하는 쿼리가 있는 경우 `*`를 필요한 열을 포함하는 목록으로 변경해야 합니다.

`ORDER BY` 절은 정렬된 순서로 쿼리 결과를 반환합니다. 더 많은 양의 데이터를 정렬할 때 필요한 메모리를 사용할 수 없는 경우 중간 정렬 결과가 디스크에 기록되어 쿼리 실행 속도가 느려질 수 있습니다. 결과를 정렬할 필요가 없는 경우 `ORDER BY` 절을 추가하지 않습니다. 또한 필요한 쿼리가 아닌 경우 내부 쿼리에 `ORDER BY`를 추가하지 않습니다.

### 창 함수 범위 축소
<a name="query-optimization-windows"></a>

[창 함수](https://trino.io/docs/current/functions/window.html)는 결과를 계산하기 위해 작업하는 모든 레코드를 메모리에 보관합니다. 창 크기가 너무 크면 창 함수의 메모리가 부족해질 수 있습니다. 사용 가능한 메모리 한도 내에서 쿼리를 실행하려면 `PARTITION BY` 절을 추가하여 창 함수가 작동하는 창 크기를 줄입니다.

창 함수가 있는 쿼리를 창 함수 없이 다시 작성할 수도 있습니다. 예를 들어 `row_number` 또는 `rank`를 사용하는 대신 [https://trino.io/docs/current/functions/aggregate.html#max_by](https://trino.io/docs/current/functions/aggregate.html#max_by) 또는 [https://trino.io/docs/current/functions/aggregate.html#min_by](https://trino.io/docs/current/functions/aggregate.html#min_by)와 같은 집계 함수를 사용할 수 있습니다.

다음 쿼리는 `max_by`를 사용하여 각 KMS 키에 가장 최근에 할당된 별칭을 찾습니다.

```
SELECT element_at(requestParameters, 'targetKeyId') as keyId, 
max_by(element_at(requestParameters, 'aliasName'), eventTime) as mostRecentAlias 
FROM $EDS_ID 
WHERE eventsource = 'kms.amazonaws.com' 
AND eventName in ('CreateAlias', 'UpdateAlias') 
AND eventTime > DATE_ADD('week', -1, CURRENT_TIMESTAMP) 
GROUP BY element_at(requestParameters, 'targetKeyId')
```

이 경우 `max_by` 함수는 그룹 내의 최신 이벤트 시간과 함께 레코드의 별칭을 반환합니다. 이 쿼리는 창 함수를 사용하는 동등한 쿼리보다 실행 속도가 빠르고 메모리 사용량도 적습니다.

## 쿼리 실패에 대한 해결 방법
<a name="lake-queries-troubleshooting"></a>

이 섹션에서는 일반적인 쿼리 실패에 대한 해결 방법을 제공합니다.

**Topics**
+ [응답이 너무 커서 쿼리 실패](#large-responses)
+ [리소스 소진으로 인한 쿼리 실패](#exhausted-resources)

### 응답이 너무 커서 쿼리 실패
<a name="large-responses"></a>

응답이 너무 큰 경우 쿼리가 실패할 수 있으며 이때 `Query response is too large`라는 메시지가 표시됩니다. 이 경우 집계 범위를 줄일 수 있습니다.

`array_agg` 같은 집계 함수는 쿼리 응답에서 하나 이상의 열이 매우 커서 쿼리가 실패할 수 있습니다. 예를 들어 `array_agg(DISTINCT eventName)` 대신 `array_agg(eventName)`을 사용하면 선택한 CloudTrail 이벤트의 중복 이벤트 이름으로 인해 응답 크기가 많이 증가합니다.

### 리소스 소진으로 인한 쿼리 실패
<a name="exhausted-resources"></a>

조인, 집계 및 창 함수와 같은 메모리 집약적 작업을 실행하는 동안 충분한 메모리를 사용할 수 없는 경우 중간 결과가 디스크에 유출되지만 유출하면 쿼리 실행 속도가 느려지고 쿼리가 `Query exhausted resources at this scale factor`를 통해 실패하지 않도록 방지하기에 충분하지 않을 수 있습니다. 쿼리를 다시 시도하여 이 문제를 해결할 수 있습니다.

쿼리를 최적화한 후에도 위 오류가 지속되면 이벤트의 `eventTime`을 사용하여 쿼리의 범위를 좁히고 원래 쿼리 시간 범위의 더 작은 간격으로 쿼리를 여러 번 실행할 수 있습니다.