

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# 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` 関数のパフォーマンスを向上させることができます。例えば、各 で タイプのイベント数を取得しながら AWS リージョン、 `eventName`を使用してパフォーマンスを向上させることができます。 よりも の一意の値が多い`eventName`ため`awsRegion`、 ではなく `GROUP BY`関数で`awsRegion`順序`eventName`付けします`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` 条件を使用して結果を少数の行に制限します。そうしないと、クエリは大きな結果を返し、クエリの実行により多くの時間がかかります。

`LIMIT` を `ORDER BY` とともに使用すると、ソートに必要なメモリ量と所要時間が減るため、上位または下位の 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` は、2 つのクエリの結果を 1 つの結果にまとめる 2 つの方法ですが、`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` のような集計関数を使用すると、クエリレスポンス内の少なくとも 1 つの行が非常に大きくなり、クエリが失敗する可能性があります。例えば、`array_agg(DISTINCT eventName)` の代わりに `array_agg(eventName)` を使用すると、選択した CloudTrail イベントからのイベント名が重複しているため、レスポンスサイズが大幅に増加します。

### リソースの枯渇によりクエリが失敗する
<a name="exhausted-resources"></a>

結合、集計、ウィンドウ関数などのメモリを大量に消費するオペレーションの実行中に十分なメモリが利用できない場合、中間結果がディスクにスピルされますが、スピルによりクエリの実行が遅くなり、クエリが `Query exhausted resources at this scale factor` で失敗するのを防ぐには不十分になる可能性があります。これは、クエリを再試行することで修正できます。

上記のエラーがクエリの最適化後も続く場合は、イベントの `eventTime` を使用してクエリの範囲を絞り込み、元のクエリ時間範囲のより短い間隔でクエリを複数回実行できます。