クエリによって消費されるメモリリソースがシステムクォータを超えると、システムはメモリ不足 (OOM) エラーを報告します。このトピックでは、メモリ使用量のクエリ方法、高メモリ使用量の分析方法、および OOM エラーの特定方法について説明します。また、OOM エラーの原因と解決策についても説明します。
メモリ使用量を分析するにはどうすればよいですか?
メモリ使用量を表示する
Hologres コンソールでインスタンスの合計メモリ使用量を表示できます。Hologres インスタンス内のすべてのノードのメモリ使用量の値が集計されます。詳細については、「Hologres メトリクス」をご参照ください。
低速クエリログの memory_bytes フィールドには、単一クエリのメモリ使用量が示されます。フィールド値は参考値であり、不正確な場合があります。詳細については、「低速クエリログのクエリと分析」をご参照ください。
高メモリ使用量への対処
[Hologres コンソール] で
メモリ使用量
およびインスタンスメモリ分散使用量
メトリックを表示できます。詳細については、「Hologres メトリック」をご参照ください。メモリ使用量が長時間 80% を超えている場合、インスタンスのメモリ使用量は高いと見なされます。 Hologres では、メモリリソースは予約されています。クエリが実行されていない場合でも、一部のメタデータ、インデックスデータ、およびキャッシュデータはメモリリソースを消費します。メタデータは計算速度の向上に役立ちます。この場合、30% から 50% のメモリ使用量は正常です。メモリ使用量が上昇し続け、100% に近づくと、システムパフォーマンス、インスタンスの安定性、およびインスタンスのパフォーマンスが低下する可能性があります。このセクションでは、この問題の考えられる原因、影響、および解決策について説明します。原因
メタデータが過剰なメモリを占有している。
テーブル数とデータ量が増加するにつれて、メタデータによって消費されるメモリリソースも増加します。この場合、クエリが実行されていなくても、メモリ使用量は増加します。各テーブルグループには、子パーティションテーブルを含み、外部テーブルを含まない、10,000 以下のテーブルを含めることをお勧めします。テーブルグループに含まれるシャードが多いほど、生成されるパーツとメタデータが多くなり、メタデータによって消費されるメモリリソースが多くなります。
計算に過剰なメモリリソースが消費されている。
大量の Count Distinct 操作、複雑な JOIN 操作、複数のフィールドに基づく GROUP BY 操作、ウィンドウ操作などのシナリオでは、大量のデータをスキャンする必要があるか、計算ロジックが非常に複雑です。この場合、計算に過剰なメモリリソースが消費されます。
影響
安定性への影響
大量のメタデータがクエリに使用可能なメモリ空間を占有している場合、クエリ中に
SERVER_INTERNAL_ERROR、ERPC_ERROR_CONNECTION_CLOSED、および既存のすべてのクエリで使用される合計メモリがメモリ制限を超えました
などのエラーが発生する可能性があります。パフォーマンスへの影響
大量のメタデータがクエリに使用可能なキャッシュ領域を占有している場合、キャッシュヒット数が減少し、クエリレイテンシが増加します。
解決策
過剰なメタデータが原因でインスタンスのメモリ使用量が多い場合は、
hg_table_info
テーブルに基づいてテーブルを管理します。詳細については、「テーブル統計のクエリと分析」をご参照ください。不要なデータとテーブルを削除し、テーブルパーティション操作を減らして、メモリリソースを解放することをお勧めします。複雑な計算が原因でインスタンスのメモリ使用量が多い場合は、データの読み取りとデータの書き込み用に SQL ステートメントを個別に最適化することをお勧めします。詳細については、このトピックの「クエリで OOM エラーが報告された場合はどうすればよいですか?」セクションと「データのインポートまたはエクスポート中に OOM エラーが報告された場合はどうすればよいですか?」セクションをご参照ください。
インスタンスをスケールアウトして、コンピューティングリソースとストレージリソースを増やします。詳細については、「インスタンスリスト」をご参照ください。
OOM エラーを特定するにはどうすればよいですか?
計算に消費されるメモリリソースのサイズが 20 GB に達するか超えると、OOM エラーが報告されます。次のエラーメッセージは例です。
既存のすべてのクエリで使用される合計メモリがメモリ制限を超えました。
既存のクエリのメモリ使用量 =(2031xxxx、184yy)(2021yyyy、85yy)(1021121xxxx、6yy)(2021xxx、18yy)(202xxxx、14yy)。使用/制限:xy1 / xy2 クォータ/合計クォータ:zz / 100
エラーには次の部分が含まれています。
queries=(2031xxxx,184yy)
この部分は
queries=(query_id,消費されたメモリサイズ)
の形式です。たとえば、queries=(2031xxxx,18441803528)
は、ID が2031xxxx
のクエリがノードの 18 GB のメモリを消費していることを示します。エラー情報には、最も多くのメモリリソースを消費する上位 5 つのクエリの ID が表示されます。「スロークエリログのクエリと分析」の手順に従って、クエリの詳細を表示できます。使用済み/制限: xy1/xy2
この部分では、使用済み/制限は、ノードの
計算に消費されたメモリリソース/計算の最大メモリリソース
を表します。2 つの値はどちらもバイト単位です。計算に消費されたメモリリソース は、ノードで進行中のすべてのクエリによって計算に消費される合計メモリリソースを示します。たとえば、使用済み/制限: 33288093696/33114697728
は、進行中のすべてのクエリがノードの 33.2 GB のメモリを消費し、ノードの計算のメモリリソースの上限が 33.1 GB であることを示します。その結果、OOM エラーが発生します。クォータ/合計クォータ: zz/100
この部分では、
クォータ
はリソースグループを示し、zz
はリソースグループに割り当てられたリソースの割合を示します。たとえば、クォータ/合計クォータ: 50/100
は、Hologres インスタンスにリソースグループが構成されており、インスタンスリソース全体の 50% がリソースグループに割り当てられていることを示します。
OOM エラーの原因は何ですか?
一部のシステムでは、メモリリソースが不足している場合、ディスクへのスピル・メカニズムを実装するためにデータをディスクにキャッシュする場合があります。クエリ効率を向上させるために、Hologres はクエリ内のすべての演算子にメモリリソースを使用します。その結果、メモリリソースの不足により OOM エラーが発生します。
メモリリソースの割り当てと制限
Hologres インスタンスは、複数のノードを含む分散システムです。インスタンス内のノード数は、インスタンスタイプによって異なります。詳細については、「インスタンスの仕様」をご参照ください。
Hologres インスタンスの各ノードには、16 個の CPU コアと 64 GB のメモリが割り当てられます。クエリ中にノードのメモリリソースが不足すると、OOM エラーが発生します。メモリリソースは、クエリ、バックエンドプロセス、キャッシュされたデータ、およびメタデータによって消費されます。 V1.1.24 より前の Hologres バージョンでは、ワーカーノードで最大 20 GB のメモリを使用できます。Hologres V1.1.24 以降、この制限は削除され、システムはメモリリソースを動的に調整します。システムはノードのメモリ使用量を定期的にチェックし、少量のメタデータが存在する場合、可能な限り多くの使用可能なメモリリソースをクエリに割り当てます。これにより、クエリ用に十分なメモリリソースを予約できます。
クエリで OOM エラーが報告された場合はどうすればよいですか?
クエリでは、次のいずれかの理由により、OOM エラーが報告される場合があります。
実行プランが不適切です。収集された統計が無効であるか、結合順序が無効です。
多数のクエリが同時に実行され、各クエリが大量のメモリリソースを消費します。
クエリが複雑であるか、大量のデータをスキャンする必要があります。
クエリに
UNION ALL
キーワードが含まれており、エグゼキュータの並列処理が増加します。インスタンスにリソースグループが構成されていますが、リソースグループに割り当てられているリソースはごくわずかです。
データの偏り問題が発生したか、シャードプルーニングが有効になっているため、負荷のバランスが崩れています。一部のノードにはメモリリソースが不足しています。
このセクションでは、各原因の詳細と関連する解決策について説明します。
リソースグループに割り当てられたリソースが不十分
サーバーレスコンピューティング機能を使用してクエリを実行します。サーバーレスコンピューティング機能を使用すると、インスタンス専用の排他的リソースではなく、サーバーレスコンピューティングリソースを使用してクエリを実行できます。サーバーレスコンピューティング機能は、インスタンスの排他的リソースの量よりも多くのコンピューティングリソースを提供し、クエリはリソースを競合する必要がありません。これにより、OOM 問題を解決できます。サーバーレスコンピューティング機能の詳細については、「サーバーレスコンピューティングの概要」をご参照ください。サーバーレスコンピューティング機能の使用方法の詳細については、「サーバーレスコンピューティングのユーザーガイド」をご参照ください。
V3.0 以降、Hologres はクエリキューに基づいてサーバーレスコンピューティングリソースを使用して OOM クエリを自動的に再実行できます。 SQL 文で計算リソースタイプを手動で指定する必要はありません。詳細については、「大規模クエリの制御」をご参照ください。
不適切な実行プラン
タイプ 1:無効な統計
explain <SQL>
文を実行して、実行計画をクエリします。次の図に示すrows=1000
は、統計が欠落しているか無効であることを示します。この場合、生成された実行計画が不適切であり、計算に大量のメモリリソースが消費されます。その結果、OOM エラーが発生します。解決策:
analyze <tablename>
文を実行して、統計を更新します。自動分析機能を使用して、統計の自動更新を有効にします。詳細については、「ANALYZE と自動分析」をご参照ください。
タイプ 2:無効な結合順序
2 つのテーブルでハッシュ結合操作を実行する場合、データ量の少ないテーブルに基づいてハッシュテーブルを生成するのが妥当です。
explain <SQL>
文を実行して、実行計画をクエリできます。次の図に示すように、データ量の少ないテーブルがデータ量の多いテーブルの上に表示されている場合、データ量の多いテーブルを使用してハッシュテーブルが生成されます。この場合、結合順序が無効であり、OOM エラーが発生する可能性があります。考えられる原因:テーブル統計がタイムリーに更新されていません。次の図に示す例では、実行計画が生成される前に、赤い四角で囲まれた最初のテーブルのデータ行数が更新されていません。その結果、
rows=1000
と表示されますが、これは無効です。オプティマイザが最適な実行プランを生成できません。
解決策:
結合するテーブルで
analyze <tablename>
文を実行して、統計をタイムリーに更新します。これにより、有効な結合順序を生成できます。analyze <tablename>
文を実行した後も生成された結合順序が無効な場合は、関連する Grand Unified Configuration (GUC) パラメーターを変更します。たとえば、optimizer_join_order=query
設定を構成して、オプティマイザーが SQL 文に基づいて結合順序を決定できるようにします。この方法は、複雑なクエリに適しています。SET optimizer_join_order = query; SELECT * FROM a JOIN b ON a.id = b.id; -- ハッシュテーブルのビルド側としてテーブル b を使用します。
ビジネス要件に基づいて結合順序を調整することもできます。
構文
説明
set optimizer_join_order = <value>
オプティマイザが使用する結合順序アルゴリズムを指定します。有効な 値:
query:SQL ステートメントで指定された結合順序を使用します。このアルゴリズムは、オプティマイザのオーバーヘッドが最も少なくなります。
greedy:貪欲アルゴリズムを使用して、より良い結合順序を取得します。このアルゴリズムは、オプティマイザのオーバーヘッドが中程度です。
exhaustive:動的計画アルゴリズムを使用して、最適な結合順序を取得します。これはデフォルト値であり、最適な実行プランを生成します。ただし、このアルゴリズムは、オプティマイザのオーバーヘッドが最も大きくなります。
タイプ 3:不正確なデータサイズ推定
結合操作では通常、小さなテーブルまたはデータサイズの小さいサブクエリをビルド側として使用して、ハッシュテーブルを生成します。これにより、パフォーマンスが最適化され、メモリリソースが節約されます。ただし、クエリが複雑すぎるか、統計が無効な場合、推定データサイズが不正確になり、大きなテーブルまたはデータサイズの大きいサブクエリがビルド側として使用されます。この場合、ハッシュテーブルの生成に過剰なメモリリソースが消費され、OOM エラーが発生します。
次の図では、
Hash (cost=727353.45..627353.35 , rows=970902134 width=94)
はビルド側を示し、rows=970902134
はハッシュテーブルの生成に使用される推定データサイズを示します。実際のデータサイズが小さい場合、推定結果は不正確です。解決策:
サブクエリが実行されるテーブルの統計が更新されているかどうか、または既存の統計が有効かどうかを確認します。無効な場合は、
analyze <tablename>
文を実行します。次の GUC パラメータを使用して、ハッシュテーブルのデータサイズ推定を無効にします。
説明デフォルトでは、この推定は無効になっています。最適化のために有効にすることができます。必要に応じて無効にすることができます。
SET hg_experimental_enable_estimate_hash_table_size = off;
タイプ 4:大きなテーブルのブロードキャスト
ブロードキャスト操作は、テーブルのデータをすべてのシャードに複製します。ブロードキャストモーション演算子は、シャード数とブロードキャストテーブル数の両方が少ないシナリオでのみ優れています。結合操作の実行プランでは、最初にブロードキャスト操作が実行されます。ビルド側データがブロードキャストされた後に、ハッシュテーブルが生成されます。この場合、各シャードでハッシュテーブルの生成に使用されるデータは、ビルド側データ全体です。多数のシャードが存在する場合、またはデータサイズが大きい場合、過剰なメモリリソースが消費され、OOM エラーが発生します。
次の図に示す実行プランでは、推定データ行数は 1 で、80 データ行がブロードキャストに使用されます。ただし、テーブルには 80,000,000 データ行が含まれています。これらのすべてのデータ行は実際の操作中にブロードキャストされ、過剰なメモリリソースを消費します。その結果、OOM エラーが発生します。
解決策:
実行計画の推定データ行数が有効かどうかを確認します。推定数が無効な場合は、
analyze <tablename>
文を実行して統計を更新します。次の GUC パラメータを使用して、ブロードキャストを無効にし、代わりに再配布演算子を使用します。
SET optimizer_enable_motion_broadcast = off;
高いクエリ同時実行性
単一クエリに消費されるメモリサイズが小さい場合でも、クエリ/秒 (QPS) メトリックの値が大幅に増加しているか、
HGERR_detl 既存のクエリのメモリ使用量 = (2031xxxx,184yy)(2021yyyy,85yy)(1021121xxxx,6yy)(2021xxx,18yy)(202xxxx,14yy);
のようなエラーが返された場合、クエリ同時実行性が高いと見なされます。この場合、次の解決策を使用できます。データ書き込みの同時実行性を減らします。詳細については、このトピックの「データのインポートまたはエクスポート中に OOM エラーが報告された場合はどうすればよいですか?」セクションをご参照ください。
マルチインスタンス高可用性デプロイメントを実装します。詳細については、「プライマリインスタンスとセカンダリインスタンスの読み取り/書き込み分割を構成する (共有ストレージ)」をご参照ください。
インスタンスのワーカーノードの数を増やします。
複雑なクエリ
クエリが複雑であるか、大量のデータをスキャンする必要があるために単一クエリで OOM エラーが発生した場合は、次の解決策を使用できます。
クレンジングされたデータを Hologres に書き込んで、事前計算を実装します。これにより、Hologres で大量のデータに対する抽出、変換、ロード (ETL) 操作が回避されます。
クエリにフィルタ条件を追加します。
固定プランまたは COUNT DISTINCT 演算子を使用して、SQL ステートメントを最適化します。詳細については、「クエリパフォーマンスの最適化」をご参照ください。
UNION ALL
次のサンプル文には、
UNION ALL
キーワードを使用する多数のサブクエリが含まれています。この場合、エグゼキュータは各サブクエリ
を同時に処理する必要があり、過剰なメモリリソースが必要になります。その結果、OOM エラーが発生します。subquery1 UNION ALL subquery2 UNION ALL subquery3 ...
次の GUC パラメータを使用して、エグゼキュータにシリアル実行を強制できます。これにより、OOM のリスクは軽減されますが、クエリ速度は低下します。
SET hg_experimental_hqe_union_all_type = 1; SET hg_experimental_enable_fragment_instance_delay_open = on;
不適切なリソースグループ構成
既存のクエリのメモリ使用量 = (3019xxx,37yy)(3022xxx,37yy)(3023xxx,35yy)(4015xxx,30yy)(2004xxx,2yy); 使用済み/制限: xy1/xy2 クォータ/合計クォータ: zz/100
のようなエラーメッセージが返された場合、リソースグループ設定が不適切です。次の図に示すサンプルエラーメッセージでは、zz の値は 10 です。これは、リソースグループがインスタンスリソースの 10% しか持っていないことを示します。解決策: 各リソースグループがインスタンスリソースの少なくとも
30%
を持つことができるように、リソースグループクォータを調整します。データの偏りまたはシャードプルーニング
インスタンス全体のメモリ使用量が許容範囲内であっても、OOM エラーが発生する場合があります。これは、データの偏りまたはシャードプルーニングが発生した場合に、インスタンス内の 1 つ以上のノードのメモリ使用量が多いことが原因である可能性があります。
説明シャードプルーニングは、クエリ用のプルーニング機能です。シャードプルーニングが有効になっていると、部分的なシャードのデータのみがスキャンされます。
次の SQL 文を実行して、データスキューエラーが発生しているかどうかを特定します。この文では、
hg_shard_id
はテーブルの組み込み隠しフィールドであり、テーブルが存在するシャードを示します。SELECT hg_shard_id, count(1) FROM t1 GROUP BY hg_shard_id;
実行計画からシャードプルーニングに関する情報を表示します。この例では、シャードセレクター の値は
l0[1]
です。これは、クエリ用に 1 つのシャードのみが選択されていることを示します。-- 分散キーは x です。x = 1 フィルタ条件に基づいてシャードをすばやく見つけることができます。 SELECT count(1) FROM bbb WHERE x = 1 GROUP BY y;
解決策:
適切な分散キーを使用して、データの偏りを防ぎます。
データの偏りエラーが発生した場合は、ビジネスを再構築します。
高カーディナリティ多段階 GROUP BY
Hologres V3.0 以降では、高カーディナリティデータを複数段階で集計し、分散キーが GROUP BY キーのサブセットでない場合、GROUP BY キーベースの集計後に、低段階集計の各同時インスタンスに大きなハッシュテーブルが生成されます。その結果、メモリ使用量が増加し、OOM 問題が発生する可能性があります。 GUC パラメータを構成して、異なる段階での集計操作を許可できます。
-- GUC パラメータ hg_experimental_partial_agg_hash_table_size を使用して、ハッシュテーブルの最大行数を構成します。最大値は 8192 です。デフォルト値は 0 で、ハッシュテーブルの行数に制限がないことを示します。 SET hg_experimental_partial_agg_hash_table_size = 8192;
データのインポートまたはエクスポート中に OOM エラーが報告された場合はどうすればよいですか?
2 つの Hologres テーブル間、または内部テーブルと外部テーブル間でデータをインポートおよびエクスポートできます。たとえば、MaxCompute テーブルから Hologres テーブルにデータをインポートできます。このようなシナリオでは、OOM エラーが発生する可能性があります。
サーバーレスコンピューティング機能を使用したデータのインポートまたはエクスポート
サーバーレスコンピューティング機能を使用すると、インスタンスの排他的リソースではなく、サーバーレスコンピューティングリソースを使用してデータをインポートまたはエクスポートできます。サーバーレスコンピューティング機能は、インスタンスの排他的リソースの量よりも多くのコンピューティングリソースを提供し、タスクはリソースを競合する必要がありません。これにより、OOM 問題を解決できます。サーバーレスコンピューティング機能の詳細については、「サーバーレスコンピューティングの概要」をご参照ください。サーバーレスコンピューティング機能の使用方法の詳細については、「サーバーレスコンピューティングのユーザーガイド」をご参照ください。
多数の列を持つテーブル、またはサイズの大きい列と高いスキャン同時実行性を持つテーブル
MaxCompute からデータをインポートする場合、ソース MaxCompute テーブルに多数の列が含まれている場合、またはテーブルにサイズの大きい列が含まれていてスキャン同時実行性が高い場合、OOM エラーが発生します。 GUC パラメータを使用してデータインポートの同時実行性を制御し、OOM のリスクを軽減できます。
多数の列を持つテーブル (一般的)
説明次の GUC パラメータを SQL ステートメントと一緒に使用します。少なくとも最初の 2 つのパラメータを構成することをお勧めします。 OOM エラーが解決しない場合は、より小さいパラメータ値を指定します。
-- MaxCompute テーブルを読み取る最大並列処理を構成します。デフォルト値は、インスタンスの CPU コア数と同じです。最大値は 128 です。大きな値を使用しないことをお勧めします。これにより、クエリが他のクエリに影響を与えたり、特にデータインポートシナリオでシステムの過負荷によるエラーが発生したりするのを防ぎます。このパラメータは、Hologres V1.1 以降で有効になります。 SET hg_foreign_table_executor_max_dop = 32; -- MaxCompute テーブルから一度に読み取るデータ量を構成します。デフォルト値:8192。 SET hg_experimental_query_batch_size = 4096; -- 外部テーブルからデータを読み取るときに同時に実行できる DML ステートメントの最大数を構成します。デフォルト値:32。このパラメータは、インポート操作が過剰なシステムリソースを占有するのを防ぐために、データのインポートおよびエクスポートシナリオ専用に提供されています。このパラメータは、Hologres V1.1 以降で有効になります。 SET hg_foreign_table_executor_dml_max_dop = 16; -- MaxCompute テーブルの各シャードのサイズを構成します。デフォルト値:64。単位:MB。シャードサイズは同時実行性に影響します。テーブルのサイズが大きい場合は、このパラメータの値を増やして、過剰なシャードがクエリのパフォーマンスを低下させるのを防ぐことができます。このパラメータは、Hologres V1.1 以降で有効になります。 SET hg_foreign_table_split_size = 128;
サイズの大きい列と高いスキャン同時実行性を持つテーブル
上記のパラメータの値を調整しても OOM エラーが解決しない場合は、テーブルにサイズの大きい列があるかどうかを確認します。ある場合は、パラメータ構成を調整します。
-- 単一のシャッフル操作で処理できるバッチの最大数を調整します。このパラメータは、サイズの大きい列に蓄積されるデータ量を減らすことができます。 SET hg_experimental_max_num_record_batches_in_buffer = 32; -- MaxCompute テーブルから一度に読み取るデータ量を調整します。デフォルト値:8192。 SET hg_experimental_query_batch_size = 128;
外部テーブルの重複データが多すぎる
外部テーブルに重複データが多すぎる場合、データのインポートが遅くなり、OOM エラーが発生する可能性があります。ビジネス要件に基づいてしきい値を決定できます。たとえば、100,000,000 データ行を含む外部テーブルがあるとします。 80,000,000 データ行が重複している場合、テーブルに重複データが多すぎると判断できます。
解決策:データインポートの前に外部テーブルのデータを重複除去するか、データをバッチでインポートします。これにより、大量の重複データが同時にインポートされるのを防ぎます。