はじめに

大量データのテーブル同士を結合したSQLを実行した場合、以下のようなメモリ不足のエラーが発生することがあります。

ERROR 3815: Join inner did not fit in memory [(SCHEMA1.TABLE_BIG1 x SCHEMA1.TABLE_BIG2) using TABLE_BIG1_b0 and previous join (PATH ID: 5)]

本記事では、テーブル結合によるメモリ不足のエラーが発生した場合のトラブルシューティングをご紹介します。

原因

エラーの多くは、以下が原因です。

・統計情報を一度も取得していないため、最適なアクセスパスでSQLが実行されていない。
・大きなテーブル同士を「Hash Join」で結合している。

Hash Joinによるエラーの原因

結合方法

テーブルの結合方法には、「Hash Join」と「Merge Join」の2種類あります。SQL実行時にどちらの結合方法を使用するかは、Verticaのオプティマイザが判断します。

それぞれの結合方法の仕組みについては、以下をご確認ください。

・テーブルの内部的な結合処理について(HASH JOIN,MERGE JOIN)
http://vertica-tech.ashisuto.co.jp/join_type-2/

エラー発生までの流れ

「Hash Join」では、HASHテーブルを使って結合を行いますが、HASHテーブルはメモリ上またはディスク上で作成されます。(下の図の赤枠)



続いて、HASHテーブルを使って結合した結果セット(HASHテーブル②)をメモリ上に作成します。この処理は必ずメモリ上で行われます。メモリ上に乗り切らない場合は、エラーが発生します。



対処方法

対処方法は以下が考えられます。①→⑥の順に対応の難易度は高くなります。

① 何もしない(経過観察)
② 運用方法の検討(利用者のアクセス制御)
③ 統計情報の取得とプロジェクション最適化の実行
④ クエリスペシフィックプロジェクションの作成
⑤ SQLのチューニング
⑥ 物理メモリの増設

各対処方法の説明やメリット・デメリットは、以下のとおりです。
対処方法説明
①何もしない(経過観察)エラーの発生頻度が少ないようであれば、様子をみることも選択肢として挙げられる。

メリット:作業工数が発生しない。
デメリット:繁忙期の場合などに、エラーが多発する可能性が考えられる。
②運用方法の検討(利用者のアクセス制御)特定のSQLで発生している場合は、SQLを発行している利用者のアクセスを制御する等、運用での回避も考えられる。

メリット:作業工数は発生しない。
デメリット:システムを利用したいタイミングで、使うことができない。
③統計情報の取得と
プロジェクション最適化の実行
一度もテーブルの統計情報取得と最適化が実行されていない場合は、統計情報の取得と最適化を実行する。

メリット:Verticaのコマンド実行やツール操作(admintoolsやMC)による対応のため、SQLの改修に比べて、作業工数を抑えることができる。
デメリット:データ量によっては最適化の完了までに時間がかかる。
④クエリスペシフィックプロジェクションの作成特定のSQLで発生している場合は、クエリスペシフイックプロジェクションを作成して、処理に必要なメモリサイズが小さくなるようにする。

メリット:Verticaのコマンド実行やツール操作(admintoolsやMC)による対応のため、SQLの改修に比べて、作業工数を抑えることができる。
デメリット:他のSQL性能に影響を与えないかテストの必要がある。
⑤SQLのチューニング特定のSQLで発生している場合は、SQLの構造を見直して、処理に必要なメモリサイズを小さくするように改修する。

メリット:SQLのメモリ使用量を減らすことにより、根本的な解決につながると考えられる。
デメリット:改修に大きな工数がかかると予想される。
⑥物理メモリの増設各ノードのメモリを増設する。

メリット:根本的な解決につながると考えられる。
デメリット:メモリ増設にあたり、費用が発生する。

これらの対処方法の中で、Vertica側での対応が必要な③~⑤の手順をご説明します。
難易度の低い③から対応し、解消しない場合は④、⑤の順で対応することをお薦めします。

対処方法③ 統計情報の取得とプロジェクション最適化の実行

一度もテーブルの統計情報取得と最適化が実行されていない場合は、統計情報の取得と最適化を実行することでエラーが解消する可能性があります。以下の手順で行います。

Step1:実行計画の確認
Step2:統計情報の取得、最適化の実行
Step3:SQLの再実行
Step4:実行計画の確認
Step5:SQLのメモリ使用量を確認

Step1:実行計画の確認

SQLの実行計画を取得し、統計情報と最適化の状態を確認します。

実行計画の確認方法は、以下をご確認ください。

・SQLの実行計画を確認する方法
http://vertica-tech.ashisuto.co.jp/sql-plan/


上の実行計画を確認すると、(NO STATISTICS) の出力が確認できます。(NO STATISTICS) は、統計情報が一度も取得されていないことを表します。

また、プロジェクションの名前は、_super となっていることが確認できます。_super はテーブルにデータをロードした直後に生成されるプロジェクションの名前のため、最適化が行われていないことが分かります。

Step2:統計情報の取得、最適化の実行

統計情報の取得とプロジェクションの最適化を実行します。手順は以下をご確認ください。
※プロジェクションの最適化を実行するとき、オプションで統計情報も一緒に取得することが可能です。

・手動で統計情報を取得する方法
 http://vertica-tech.ashisuto.co.jp/collect_analyze/

・データベースデザイナを使用してテーブル単位でプロジェクションを最適化する
 http://vertica-tech.ashisuto.co.jp/table_dbd/

Step3:SQLの再実行

SQLを再実行して、エラーが解消されたことを確認します。

Step4:実行計画の確認

再度実行計画を取得して、統計情報と最適化の状態を確認します。


Step1 で確認した(NO STATISTICS) の出力が消えています。統計情報が取得されたことが分かります。

また、プロジェクションの名前も、_super から_rep に変更されています。プロジェクションの最適化が実行されたことが分かります。

※”rep”はレプリケーションの略です。複数ノード構成の場合はセグメンテーションの略で”seg”と出力される場合もあります。セグメンテーションについては、以下をご確認ください。
 ・セグメンテーションとレプリケーションの概要
  http://vertica-tech.ashisuto.co.jp/segmentation_replication_overview/

Step5:SQLのメモリ使用量を確認

エラー発生時のSQLとStep3で実行したSQLのメモリ使用量を比較し、Step3で実行したSQLのメモリ使用量が少なくなっていることを確認します。

query_requestsシステムテーブルからメモリ使用量を確認することができます。以下はコマンドの例です。このコマンドは、SQLの開始時間、終了時間、SQL文、実行時間、メモリ使用サイズが確認できます。


query_requestsシステムテーブルで参照できる情報については、以下マニュアルをご確認ください。

・QUERY_REQUESTS
https://www.vertica.com/docs/12.0.x/HTML/Content/Authoring/SQLReferenceManual/SystemTables/MONITOR/QUERY_REQUESTS.htm

対処方法④ クエリスペシフィックプロジェクションの作成

特定のSQLで発生している場合は、クエリスペシフイックプロジェクションを作成することで、エラーが解消する可能性があります。クエリスペシフイックプロジェクションで結合列がソートされ、結合方法に「Merge Join」が使用されるようになる場合があります。

クエリスペシフィックプロジェクションは、Administration Tools、またはManagement Consoleを使用して作成できます。作成方法は以下をご確認ください。

・Administration Toolsを利用したクエリスペシフィックプロジェクションの作成方法
http://vertica-tech.ashisuto.co.jp/create-query-specific-projection-admintools/

・Management Consoleを利用したクエリスペシフィックプロジェクションの作成方法
http://vertica-tech.ashisuto.co.jp/create-query-specific-projection/

クエリスペシフィックプロジェクションを作成した後、SQLを再実行して、エラーが解消されたことをご確認ください。

対処方法⑤ SQLのチューニング

特定のSQLで発生している場合、SQLの構造を見直して処理に必要なメモリサイズを小さくすることで、エラーが解消する可能性があります。

チューニングの検討ポイントは、以下です。

1)SQLの中で選択している不要なカラムがある場合は取り除き、必要なカラムのみを選択する。
2)中間結果セットが小さくなるよう結合順序を変更する、もしくはSQLを分割する。
3)JOINを実行しないようにSQLを変更する。
4)Hash JoinではなくMerge Joinが使用されるように実行計画を変更する。

1)~3)は、Vertica独自の改修方法はなく、通常のSQLチューニングとなりますので、試行錯誤しながらの改修となります。4)は、Vertica独自の改修方法がありますので、ここでは4)についてご説明します。

改修前のSQLの実行計画を確認すると、結合キー列(c1)がソートされていないため、「Hash Join」が選択されていることが分かります。


「Merge Join」が使用されるようにするためのSQL改修方法は2つあります。

・結合列をソートするように改修
・SQLヒントを指定するように改修

結合列をソートするように改修

order by句を使用して、結合列をソートすることで、「Merge Join」が使用されるようになります。


SQLヒントを指定するように改修

JTYPEヒントを使用して、「Merge Join」が使用されるよう指定します。

※JTYPEヒントを使用する時は、SYNTACTIC_JOINヒントも含める必要があります。
 SYNTACTIC_JOINヒントがない場合は、ヒントは無視されますのでご注意ください。


JTYPEヒントで指定できる結合タイプ
FM:強制的にMerge Joinで処理。マージを実行する前に、結合対象の列を再ソートする。
H:「Hash Join」で処理。
M:「Merge Join」で処理。結合対象の列がソートされている場合のみ有効。ソートされていない場合は、Verticaは無視する。

JTYPE(FM)の制約事項
・FMは、単純な結合処理でのみ有効。
・結合対象の列は、データ型、精度、スケールが同じでなければならない。
 文字列型のカラム長は異なっていてもかまわない。

検証バージョンについて

この記事の内容はVertica 12.0で確認しています。

更新履歴

2022/08/19 本記事を公開