

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

# Amazon EMR の Trino ベストプラクティス
<a name="emr-trino-advanced"></a>

Trino のアーキテクチャは、コーディネーターワーカーモデルに従って、複数のデータソースにまたがる大規模なデータセットに対して高速で分散された SQL クエリを実行するように設計されています。コーディネーターワーカーモデルでは、各コンポーネントにクエリ実行における特殊な役割があります。Trino を実行している Amazon EMR クラスターを最高のパフォーマンスのために設定するために、いくつかの領域またはカテゴリに集中できます。これには以下が含まれます。
+ メモリ最適化のためのクラスター構成設定の調整。
+ データパーティショニングとデータ分散の設定を最適化します。
+ 動的フィルタリングを使用してクエリ結果の数を減らします。

これらの設定の一部は、Amazon EMR で Trino を使用すると自動的に調整されます。その他は、コンソールまたは CLI コマンドを使用して手動で設定できます。このセクションのトピックは、データとクラスターを最適に設定するのに役立ちます。

**Topics**
+ [パフォーマンス向上の主な重点分野](emr-trino-performance-areas.md)
+ [テーブル統計を収集して使用する](emr-trino-performance-areas-collect-stats.md)
+ [Trino ワークロードをスケーリングする際の一般的な課題](emr-trino-common-issues.md)

# パフォーマンス向上の主な重点分野
<a name="emr-trino-performance-areas"></a>

Trino は、クエリの並列性とメモリの最適化を最大化します。このアーキテクチャは、効率的にスケーリングしながら、複数のさまざまなデータソースをクエリできるようにすることで、柔軟性を提供します。Trino のパフォーマンス向上の主な分野には、以下が含まれます。

## メモリの最適化
<a name="emr-trino-performance-areas-optimization"></a>

Trino でのメモリ管理は、特に大規模で複雑なクエリを実行する場合に、高パフォーマンスと安定性を達成するために不可欠です。Trino は分散メモリモデルを使用します。このモデルでは、タスク、集約、結合、およびその他のオペレーションを処理するために、ワーカーノード間でメモリが割り当てられます。以下のリストでは、これらの設定のコレクションを紹介します:
+ **query.max-memory** – クラスター全体で 1 つのクエリに使用できる最大メモリを設定します。これはハード制限です。クエリがこのメモリを超えると失敗します。
+ **query.max-memory-per-node** – クエリが各ワーカーノードで消費できる最大メモリを定義します。これを設定することにより、単一のクエリがワーカーのリソースを独占することはありません。
+ **JVM ヒープサイズ** – JVM レベルで設定され、各ノードの Trino サーバープロセスの最大ヒープサイズを設定します。この値は、通常、JVM レベルでシステムがメモリ不足にならないように、Trino のメモリ関連の設定 (**max-memory-per-node** と **memory.heap-headroom-per-node** の合計) よりも大きくする必要があります。
+ **memory.heap-headroom-per-node** – 非クエリオペレーションのために JVM ヒープサイズから残すメモリのバッファ量を指定します。これは、内部オペレーションとガベージコレクションに十分なオーバーヘッドを確保するために不可欠です。

## 動的フィルタリング
<a name="emr-trino-performance-areas-dynamic"></a>

Trino の動的フィルタリングは、特に結合中に処理されるデータ量を減らすことでクエリのパフォーマンスを向上させる最適化手法です。フィルタ条件を動的に適用して、結合の一方の側でスキャンされたデータを、もう一方の側で見られるデータに基づいて制限します。これは、結合の一方の側が非常に選択的である (つまり、データの小さなサブセットを含む) クエリで特に便利です。Amazon EMR ではデフォルトで有効になっています。以下はクエリの例です。

```
SELECT orders.order_id, orders.total_amount
FROM orders
JOIN customers ON orders.customer_id = customers.customer_id
WHERE customers.country = 'France';
```

動的フィルタリングがない場合、Trino は、少数の顧客 (フランスからの顧客) のサブセットのみが関連している場合でも、結合で注文テーブル全体をスキャンします。このアプローチは、**注文**テーブルのすべての行を読み取るため、I/O と処理コストが高くなります。動的フィルタリングでは、Trino は最初に小さな**顧客**テーブルをスキャンし、フランスから顧客のみの customer\$1id 値を取得し、このサブセットを注文のフィルターとして適用します。つまり、フィルタリングされたサブセットに一致する customer\$1id を持つ**注文**の関連する行のみがスキャンされ、処理されるレコードが大幅に削減されます。

## スピルからディスクへ
<a name="emr-trino-performance-areas-spill"></a>

 Trino では、ディスクのスピルにより、中間クエリ結果をディスクにオフロードできるので、メモリを大量に消費するクエリは、`query_max_memory` または `query_max_memory_per_node` によって設定されたメモリ制限を超えた場合でも完了できます。デフォルトでは、Trino はこれらの制限を適用して、公平なメモリ割り当てを確保し、クラスターのデッドロックを防ぎます。ただし、大きなクエリがこれらの制限を超えると、終了のリスクがあります。ディスクのスピリングでは、`revocable memory` を使用してこれに対処します。これにより、リソースが他の場所で必要になった場合に取り消すことができる追加のメモリをクエリで借用できます。メモリが取り消されると、中間データがディスクにスピルされるため、クエリはメモリ制限を超えることなく処理を継続できます。ディスクに強制的にスピルされるクエリの実行時間が長くなる可能性があるので、デフォルトでは無効になっていることに注意してください。Amazon EMR でスピルを有効にするには、以下の設定を使用します:
+ `spill-enabled=true` – メモリ使用量が使用可能なしきい値を超えた場合にディスクのスピルを有効にします。
+ `spill-paths` – 流出したデータが保存されるディレクトリ `spill-paths=/mnt/spill` を定義します。

# テーブル統計を収集して使用する
<a name="emr-trino-performance-areas-collect-stats"></a>

 テーブル統計を収集することで、Trino のコストベースのオプティマイザは結合順序、フィルタープッシュダウン、パーティションプルーニングについて情報に基づいた意思決定を行うことができ、パフォーマンスが向上します。

`ANALYZE` コマンドを使用して、Hive または Iceberg テーブルの統計を収集できます:

```
ANALYZE sales;
```

このコマンドはテーブルの現在の統計を表示し、統計が最新かどうかを確認できます。結合、フィルター、またはグループ化オペレーションで使用される列のサブセットを指定することをお勧めします。

これはもう 1 つの便利なコマンドです。テーブルの現在の統計が表示され、統計が最新かどうかを確認します。

```
show stats for table_name;
```

# Trino ワークロードをスケーリングする際の一般的な課題
<a name="emr-trino-common-issues"></a>

Trino で Amazon S3 を使用する主な利点は、S3 が大規模なデータボリュームに合わせてスケールできることと、S3 のコスト効率です。ただし、大量のデータボリュームをクエリすると、関連するパフォーマンスの問題が発生することがあります。これらは、データの保存方法、良好なパフォーマンスを制限する構成設定、またはその他の理由で発生する可能性があります。 これらの問題が発生した場合、問題を回避または軽減するために実行できる効果的なステップがあります。

このセクションでは、大規模なデータボリュームのクエリパフォーマンスを向上させるために実装できる一般的な最適化のリストから始めます。その後、一般的な問題が詳細に説明され、それぞれに緩和策が提供されています。

このトピックは、次のカンファレンスプレゼンテーションから入手できます:「[Accelerate performance at scale: Best practices for Trino with Amazon S3](https://www.youtube.com/watch?v=cjUUcHlUKxQ)」。

## 大規模なデータセットのデータレイアウトの最適化
<a name="emr-trino-common-issues-practices"></a>

大規模なデータセットをクエリする場合、パフォーマンスのボトルネックはまれではありません。ただし、Trino を使用して Amazon S3 のデータをクエリする際に、有利なスタートを切るために実装できるベストプラクティスがあります。これには以下が含まれます。
+ **パーティショニング** – パーティショニングとは、階層にデータを整理し、関連する属性に基づいて関連するデータを一緒に保存することを意味します。パーティション化により、クエリが無関係なデータをスキャンする必要がなくなり、クエリのパフォーマンスが向上します。ソースデータをプレフィックスで配置する、特に日付範囲、リージョン、またはその他の属性で配置するなど、さまざまなパーティショニング戦略を使用できます。パフォーマンスを向上させるために Amazon S3 でデータをパーティション化する方法の詳細については、ブログ記事「Get [started managing partitions for Amazon S3 tables backed by the AWS Glue Data Catalog](https://aws.amazon.com/blogs/big-data/get-started-managing-partitions-for-amazon-s3-tables-backed-by-the-aws-glue-data-catalog/)」または記事[「Top 10 Performance Tuning Tips for Amazon Athena](https://aws.amazon.com/blogs/big-data/top-10-performance-tuning-tips-for-amazon-athena/)」を参照してください。
+ **バケット化** – バケット化とは、関連するデータを共通のファイルにグループ化することです。たとえば、州などの地理的リージョンに従ってデータをクエリする場合、同じファイルまたはファイルのグループ内の特定の州のすべてのデータをグループ化することで、クエリのパフォーマンスを向上させることができます。これを最適に機能させるには、例えば州や都道府県など、カーディナリティの高いデータ属性に基づいてバケットを作成します。また、クエリパターンを考慮することもできます。クエリが通常、これらの州からデータを読み取る場合、この例としては、カリフォルニアとオレゴンのデータをグループ化することが考えられます。
+ **S3 プレフィックスの管理** – Amazon S3 プレフィックスを使用してパーティショニング戦略を実装できます。例えば、特定の日付などの Amazon S3 バケットに 1 つのプレフィックスのみを使用することにより、リクエスト数が多くなり、HTTP 503 エラーが発生する可能性があります。プレフィックスを使用して条件を追加し、ソースデータをより効果的に整理することをお勧めします。詳細については、「Amazon S3 ユーザーガイド」の「[プレフィックスを使用してオブジェクトを整理する](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-prefixes.html)」を参照してください。次の簡単な例は、リクエストスループットを向上させるプレフィックス を示しています: `s3://bucket/country=US/dt=2024-06-13`。このサンプルでは、国と日付の両方がプレフィックスに含まれているため、プレフィックスに日付のみが含まれている場合よりも読み取りが少なくなります。

  HTTP 503 エラーの軽減については、このトピックで後述する *HTTP スローダウン*セクションで詳しく説明します。
+ **データサイズの最適化** – OPTIMIZE コマンドを実行して、パフォーマンスが向上するクエリに役立つ設定を行うことができます。Hive 外部テーブルに対してこれを実行するには、以下の手順に従います:
  + `OPTIMIZE` を使って以下のパラメータを使用します:`hive.non-managed-table-writes-enabled=true` 。このプロパティの詳細については、「[Hive general configuration properties](https://trino.io/docs/current/connector/hive.html#hive-general-configuration-properties)」を参照してください。
  + 次のパラメータを設定します: `SET SESSION` `catalog.non_transactional_optimize_enabled=true`
  + `OPTIMIZE` コマンドを実行します: `ALTER TABLE catalog.schema.table EXECUTE optimize(file_size_threshold => '128MB')`。この場合、`file_size_threshold` はデフォルトで 100MB です。このしきい値を上げると、サンプルに示すように、128MB 未満のファイルがマージされます。
+ **再試行の設定** – 再試行制限を引き上げることで、HTTP 503 エラーの可能性を軽減できます: `s3.max-error-retries`。これは、TrinoFileSystem API および Trino 449 バージョン以降を使用する場合に適用されます。一方、Trino で Amazon EMR を使用している場合は、EMRFS を使用して Amazon S3 にアクセスします。EMRFS では、`fs.s3.maxRetries` パラメータを変更することで廃止回数を増やすことができます。
+ **Amazon S3 ストレージクラスの選択** – ライフサイクルのさまざまな時点でデータに適したストレージクラスを選択すると、特定のデータ収集の要件に基づいて、パフォーマンスとコストの両方に役立ちます。詳細については、「Amazon S3 ドキュメント」の「[Amazon S3 ストレージクラスの理解と管理](https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.htm)」を参照してください。
+ **Iceberg への移行** – 特に小さなファイルでのクエリの実行に関するパフォーマンスの問題を軽減するためのもう 1 つの解決策は、Iceberg テーブルへの移行です。Iceberg には、小さなファイルをうまく処理する機能があります。
+ **自動データ圧縮を使用する** – Iceberg テーブルを使用する場合、 AWS Glue データカタログによる自動データ圧縮はデータサイズを最適化し、クエリパフォーマンスを向上させることができます。

## 大規模なデータセットをクエリする際の一般的な課題
<a name="emr-trino-common-issues-challenges"></a>

このセクションでは、Amazon S3 に大規模なデータセットを蓄積し、Trino でクエリを実行する時に発生する可能性がある一般的な問題のコレクションを一覧表示します。各セクションでは、問題を解決する方法、またはクエリへの影響を減らす方法を示します。以下のセクションで説明する各問題は、Hive コネクタを使用して再現およびテストされています。

### 大規模データスキャン
<a name="emr-trino-common-issues-large-scan"></a>

クエリで大規模なデータセットをスキャンする必要がある場合、クエリのパフォーマンスが低下し、ストレージコストが高くなるなどの問題が発生する可能性があります。大規模なデータボリュームは、データの急速な増加や、適切な期間内にレガシーデータを移動しない計画によって発生する可能性があります。これにより、クエリが遅くなる可能性があります。

大規模なデータセットのスキャンによるパフォーマンスのヒットを軽減するには、パーティショニングとバケット化を使用することをお勧めします:
+ パーティション分割は、属性に基づいて関連データをグループ化します。パーティショニングを効果的に使用することにより、クエリのパフォーマンスが大幅に向上します。
+ バケット化とは、特定の関連データ列に従ってファイルまたはバケットにデータをグループ化することを指します。バケット化は通常、関連するソースデータファイルを物理的にまとめることを意味します。

大規模なデータスキャンで緩和がどのように機能するかを説明するために、カリフォルニアまたはアラスカに割り当てることができる状態属性を持つレコードを持つデータを保存してクエリするとします。この状態属性はクエリ条件の 1 つです。各状態のデータを別の S3 バケットに保存するか、S3 プレフィックスを使用して状態に基づいてデータをパーティション化することで、クエリのパフォーマンスを向上させることができます。このパーティショニングとバケット化は、例えば日付属性などの追加の列に基づいている場合にも、パフォーマンスの向上につながる可能性があります。

**注記**  
列のカーディナリティが高く、それを使用してデータをグループ化する場合は、バケット化を使用することをお勧めします。一方、通常、パーティションキーのカーディナリティは低くしなければなりません。

**さまざまな S3 ストレージタイプの使用**

一般的に、ワークロードのパフォーマンス、データアクセス、耐障害性、コスト要件に基づいてストレージタイプを選択します。コストとパフォーマンスの間にはトレードオフが生じる可能性があります。データアクセスパターンに一致する適切な Amazon S3 ストレージクラスを選択することが重要です。主なアクセスパターンは 2 つあります:
+ 既知または予測可能な方法でアクセスされるデータ。一般的に、アクセス頻度の低いデータがある場合、コスト削減に役立つため、S3 標準 IA が適しています。頻繁にデータにアクセスしている場合、S3 Standard は Amazon EMR と Trino によるアクセスに最適です。
+ 不明または予測不可能な方法でアクセスされるデータ。これは、他の Amazon S3 ストレージクラスの使用を呼び出すことができます。S3 ストレージクラス間にはトレードオフがあります。これには、レイテンシー、ストレージコスト、可用性が含まれます。ワークロードとアクセスパターンに基づいて、適切な S3 ストレージタイプを選択できます。各クラスの利点の詳細については、「[Amazon S3 ストレージクラス]()」を参照してください。

**圧縮の使用**

Iceberg テーブルを使用することにより、Iceberg 自動圧縮を使用することもできます。これにより、ファイルサイズが最適になり、クエリ効率が向上します。詳細については、「[AWS Glue データカタログが Apache Iceberg テーブルの自動コンパクションをサポートするようになった](https://aws.amazon.com/blogs/aws/aws-glue-data-catalog-now-supports-automatic-compaction-of-apache-iceberg-tables/)」を参照してください。

### HTTP スローダウンエラー
<a name="emr-trino-common-issues-slow-network"></a>

これは、リクエストレートが Amazon S3 プレフィックスで事前設定されたしきい値を超えた場合に発生します。この状態に達したときに最も一般的に発生する HTTP エラーは、**Error 503: Please reduce your request rate** です。この問題のソースは、データを読み取るために作成する必要がある*分割*の数が多いため、多数の小さなファイルが存在する場合に根付くことができます。この問題を軽減するには、いくつかの方法があります。
+ Trino で Amazon S3 リクエストの再試行制限を引き上げます。これは、Trino 449 で `fs.s3.maxretries` を使用する EMRFS に設定されます。
+ ファイルサイズを最適化し、リクエストレートを下げることもできます。

Trino がクエリするデータセットの分割数を決定する方法の詳細については、Hive コネクタドキュメントの「[Performance tuning configuration properties](https://trino.io/docs/current/connector/hive.html#performance-tuning-configuration-properties)」を参照してください。

### 小さなファイルのクエリが困難
<a name="emr-trino-common-issues-small-files"></a>

多くの小さなファイルをクエリすることにより、GET および LIST リクエストの数が多いため、I/O オーバーヘッドが大きくなり、クエリのパフォーマンスに悪影響を及ぼす可能性があります。ファイルサイズを最適化することにより、クエリのパフォーマンスが向上します。これを行う方法はいくつかあります:
+ より少ないサイズのファイルにデータを統合します。(通常、ファイルサイズは約 128 MB にすることをお勧めします。) これは、ETL パイプラインなどのデータを取り込むときにツールで実行することも、データを手動で統合することもできます。これらのソリューションが利用できない場合は、残りのオプションが適している可能性があります。
+ `OPTIMIZE` コマンドを実行します。
+ `SESSION` パラメータを設定します。

Iceberg には、小さなファイルを自動圧縮である大きなファイルにマージできる機能があることに注意してください。 AWS Glue データカタログで管理されるファイルで動作します。詳細については、「[AWS Glue データカタログが Apache Iceberg テーブルの自動コンパクションをサポートするようになった](https://aws.amazon.com/blogs/aws/aws-glue-data-catalog-now-supports-automatic-compaction-of-apache-iceberg-tables/)」を参照してください。

### 不要なデータを含むクエリ
<a name="emr-trino-common-issues-uneeded-data"></a>

データが大きくなるのは一般的です。そのため、データアクセスパターンを追跡し、古くなったり無関係になったりしたときにデータを適切に移動することが不可欠です。これは、データが大きくなると、クエリのパフォーマンスが時間の経過とともに低下する可能性があるためです。主に、クエリの実行時にスキャンする大量のデータが原因です。Amazon S3 およびその他の サービスは、データライフサイクル移行のガイダンスを提供します。これは、データがコールドになったときにさまざまなストレージロケーションに移動するための戦略を示しています。これを行うと、ストレージコストにも利点があります。

データ移行に加えて、実行中のクエリに関連しないソースデータの削除など、他の戦略を使用することもできます。これには、ソースデータスキーマの変更を意味する可能性があるので、多少の作業が必要になる場合があります。しかし、その肯定的な結果は、データ量を減らし、クエリを高速化することです。詳細については、「[オブジェクトのライフサイクルの管理](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html)」を参照してください。