OceanBaseデータベースは、以下の主要なカテゴリを含む、さまざまなステートメントの並列実行をサポートしています。
- 並列クエリ
- 並列DML
- 並列DDL
- 並列
LOAD DATA - 同時DDL
パラレルクエリ
主な適用シナリオ
SELECTステートメントおよびそのサブクエリ- DMLステートメント(
INSERT/UPDATE/DELETE)のクエリ部分 - 外部テーブルのクエリ
意思決定プロセス
パラレルクエリの実行に関する意思決定には、2つの重要な側面が関わります:
パラレルクエリを実行するかどうか:
- クエリで
PARALLELヒントが使用されている場合、またはセッションでパラレルクエリが有効になっている場合、あるいはTABLEプロパティで並列処理が指定されている場合、パラレルクエリが有効になります。
- クエリで
並列度の決定:
- ベーステーブルのスキャンまたはインデックスのスキャンにおけるDFOの並列度は、
PARALLELヒント、セッションの並列属性、またはTABLEプロパティによって決定されます。 - 実行時に特定のDFOがアクセスするデータがマクロブロック1つに満たないことが検出された場合、そのDFOの実行時並列度は局所的に自動的に低下します。
JOINなどの中間ノードにおけるDFOの並列度は、JOINの左側の子DFOの並列度を継承します。- 一部のDFO(例えば
ROWNUMを計算するノードなど)では並列実行が許可されていないため、それらの並列度は強制的に1に設定されます。
- ベーステーブルのスキャンまたはインデックスのスキャンにおけるDFOの並列度は、
パラレルDML
ほとんどのシナリオにおいて、パラレルDML(Parallel DML、PDMLと略称)を使用することで、データのインポート、更新、削除操作のパフォーマンスを大幅に向上させることができます。
DMLの並列度
DMLの並列度はクエリ部分の並列度と一致します。並列DMLを有効にすると、クエリ部分が自動的に並列実行されます。読み取ったデータは更新対象テーブルのパーティション位置に基づいて再配分され、複数のスレッドが並列してDMLを実行します。各スレッドは複数のパーティションを担当します。
並列度が対象テーブルのパーティション数の倍数である場合、通常最適なパフォーマンスが得られます。並列度がパーティション数を上回る場合、複数のスレッドが同一のパーティションのデータを処理します。並列度がパーティション数を下回る場合、単一のスレッドが複数のパーティションのデータを処理する可能性があり、各スレッドが処理するパーティションは重複しません。
- 並列度が対象テーブルのパーティション数を上回る場合、並列度をパーティション数の整数倍に設定することを推奨します。通常、同一のパーティションに同時にデータを挿入するスレッド数は4つを超えない方がよいです。この値を超えると拡張性が制限され、ログ同期がボトルネックとなる可能性があります。また、パーティションレベルのロック同期によるオーバヘッドも発生します。
- 並列度が対象テーブルのパーティション数を下回る場合、挿入作業の負荷が偏らないように、パーティション数を並列度の整数倍に設定することを推奨します。
インデックステーブルの処理戦略
並列DMLはインデックステーブルの自動メンテナンスをサポートします。
- ローカルインデックスの場合、ストレージ層は並列DMLによるメインテーブルの更新時にローカルインデックスを自動的に処理します。
- グローバルインデックスの場合、並列DMLフレームワークを使用すると、グローバルインデックスをメンテナンスするための対応する計画が生成されます。
以下は、2つのグローバルインデックスに対する処理フローです:
- DFO1が最初にメインテーブルの更新を担当します。
- DFO1はその後、グローバルインデックス1とグローバルインデックス2に必要なデータをDFO2に渡し、DFO2がグローバルインデックステーブル1の更新を担当します。
- 最終的に、DFO2がグローバルインデックス2に必要なデータをDFO3に渡し、DFO3がグローバルインデックステーブル2の更新を完了します。
上記の戦略はすべてのINSERT、DELETE、UPDATE文に適用されます。MERGE文の場合、インデックスのメンテナンス操作は1つのDFOで処理されます。以下の図のように:
- DFO1が最初にメインテーブルの更新を担当します。
- DFO1はその後、グローバルインデックス1とグローバルインデックス2に必要なデータをDFO2に渡し、DFO2内部で全てのグローバルインデックスのメンテナンス操作を順次完了します。
パーティションキー更新の処理戦略
UPDATE文において、メインテーブルまたはグローバルインデックステーブルのパーティションキーが更新されると、Row Movement操作が実行されます。これは、古いデータを古いパーティションから削除し、新しいデータを新しいパーティションに挿入する操作です。Row Movementが発生する際、UPDATE操作はDELETEとINSERTの2つのステップに分解されます。つまり、Row Movementを伴うUPDATE DFOは2つのDFOに分割されます。最初のDFOがDELETEを担当し、2番目のDFOがINSERTを担当します。主キーの競合を避けるため、DELETE DFOの実行が完全に終了してからでないとINSERT DFOの実行を開始できません。
トランザクション処理
OceanBaseデータベースのパラレルDMLは、通常のDMLステートメントと同様に、トランザクション処理を完全にサポートしています。パラレルDMLステートメントは他のクエリステートメントと共に同一のトランザクション内で実行でき、パラレルDMLステートメントの実行完了後、直ちにトランザクションをコミットする必要はなく、後続のクエリステートメントでその結果を読み取ることができます。
OceanBaseデータベースV4.1.0以前のバージョンでは、パラレルDMLの実行時間が長すぎる場合、テナント構成パラメータundo_retentionに適切な値を設定する必要がありました。そうでない場合、-4138 (OB_SNAPSHOT_DISCARDED)エラーが発生し、SQLが内部で繰り返し再試行され、タイムアウトする可能性がありました。
undo_retentionは文字通り、Undoの保持ポイントを意味します。つまり、現在時刻からどの程度遡った期間のUndoログを保持するかです。OceanBaseデータベースでは、この期間のすべてのデータのマルチバージョンを保持します。パラレルDMLの実行時間がundo_retentionで設定された時間を超えると、マルチバージョンデータが廃棄される可能性があります。DML内のいずれかの後続操作が廃棄されたマルチバージョンデータにアクセスしようとした場合、OB_SNAPSHOT_DISCARDEDエラーがトリガーされます。undo_retentionのデフォルト値は30分です。これは、デフォルト設定では、パラレルDMLステートメントが30分以内に実行完了できない場合、ステートメントのタイムアウト時間設定に関係なく、実行がタイムアウトしてエラーが発生する可能性があることを意味します。一般的に、業務上の最長パラレルDML実行時間が2時間の場合、undo_retentionは2.5時間に設定できます。undo_retentionを任意の大きな値に設定することはできません。そうするとマルチバージョンデータが回収されず、ディスクが満杯になる原因となります。
OceanBaseデータベースV4.1.0以降では、パラレルDMLの実行はundo_retentionの設定に依存しなくなりました。マルチバージョンデータはトランザクションのバージョン番号に基づいて回収されます。トランザクションがアクティブな限り、そのトランザクションに対応するバージョン番号で読み取れる内容は回収されません。ただし、データディスクが満杯の場合は例外であり、この場合もマルチバージョンデータは強制的に回収され、パラレルDMLはOB_SNAPSHOT_DISCARDEDエラーを受け取り、SQL全体を自動的に再試行します。
ダイレクトロード
メモリ空き容量が不足している場合、パラレルDMLはメモリ不足エラーを報告しやすいため、ダイレクトロードパスを経由しないパラレルDMLは、まずデータをMemTableに書き込み、その後ダンプとマージを経てディスクに書き込みます。パラレルDMLはデータを高速にMemTableに書き込むため、書き込み速度がダンプ速度を上回ると、メモリ使用量が増加し続け、最終的にメモリ不足エラーが発生します。
この問題を解決するため、OceanBaseデータベースのストレージ層にはダイレクトロード機能が導入されました。パラレルDMLがINSERTステートメントの実行にダイレクトロード機能を使用する場合、データは直接MemTableをバイパスしてディスクに書き込まれます。これにより、メモリ不足の問題が解消されるとともに、データインポートのパフォーマンスも向上します。
ユーザーはAPPENDヒントを使用してダイレクトロード機能を有効にできます。ダイレクトロードを開始する前に、前のトランザクションをコミットし、AUTOCOMMIT = 1を設定する必要があります。OceanBaseデータベースV4.2.0では、ダイレクトロード機能はパラレルDMLと組み合わせて使用する必要があります。ヒントまたはセッションでパラレルDMLが有効になっていない場合、ダイレクトロードのヒントは自動的に無視されます。以下は構文例です:
SET AUTOCOMMIT = 1;
INSERT /*+ APPEND ENABLE_PARALLEL_DML PARALLEL(3) */ INTO t1 SELECT * FROM t2;
パラレル化できないDML操作
正しいDMLセマンティクスを確保するため、以下のシナリオではクエリ部分はパラレル実行可能ですが、DML部分はパラレル実行できません:
- ターゲットテーブルに
LOCAL UNIQUE INDEXが含まれる場合、DML部分はパラレル実行できませんが、クエリ部分は引き続きパラレル実行可能です。 INSERT ON DUPLICATE KEY UPDATEステートメントのDML部分はパラレル実行できません。- ターゲットテーブルにトリガーや外部キーが含まれる場合、DML部分はパラレル実行できません。
- DMLで
IGNOREモードが有効になっている場合、DML部分はパラレル実行できません。 - 複数テーブルの
INSERT ALL、UPDATE、DELETE、MERGE INTOステートメントはパラレル実行できません。 - ArrayBindingバッチの最適化はパラレル実行をサポートしません。
- DBLinkはパラレル実行をサポートしません。
INSERT...VALUES...、INSERT UPDATE、REPLACEステートメントはパラレル実行をサポートしません。ON UPDATE CURRENT_TIMESTAMPを含む列はパラレル実行をサポートしません。
DMLがパラレル実行されていない場合、EXPLAIN EXTENDEDコマンドを使用してNoteフィールドを確認し、非パラレル実行の原因を特定できます。
Row Movement操作
パーティションテーブルのパーティションキーを更新する際、データがあるパーティションから別のパーティションへ移動する可能性があります。Oracleモードでは、以下のコマンドを使用してパーティション間のデータ移動を禁止できます。
CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT) PARTITION BY HASH(c1) PARTITIONS 3;
ALTER TABLE t1 DISABLE ROW MOVEMENT;
obclient> UPDATE t1 SET c1 = c1 + 100000000;
OBE-14402: updating partition key column would cause a partition change
しかし、並列DMLはテーブルのROW MOVEMENT属性を無視し、常にパーティションキーの更新を許可します。
パラレルDDL
すべてのパラレルDDL操作は、特定のParallel DMLを通じて実行されます。例えば、インデックスの作成は本質的にはインデックスの空のテーブルを作成し、次にメインテーブルからインデックス列のデータを並列してクエリし、最後にインデックステーブルに並列して挿入するプロセスです。OceanBaseデータベースでパラレル実行をサポートするDDLステートメントは以下のとおりです:
CREATE TABLE AS SELECTALTER TABLECREATE INDEX
HINTによる並列度の指定
CREATE INDEX ステートメントは PARALLEL HINTを使用して並列処理を有効にできますが、その他のDDLではセッション変数と TABLE PARALLEL 属性のみがサポートされています。
構文は以下のとおりです:
CREATE /*+ PARALLEL(3) */ INDEX IDX ON t1(c2);
SESSION変数による並列度の指定
上記のすべてのDDLステートメントは、SESSION変数を使用して並列度を指定できます。並列度を指定すると、そのセッション上のすべてのDDLが自動的に指定された並列度で並列実行され、クエリ部分と変更部分で同じ並列度が使用されます。
Oracleモードでは、
ALTER SESSIONを使用して並列度を変更します。構文例は以下のとおりです:-- 並列インデックス作成 ALTER SESSION FORCE PARALLEL DDL PARALLEL 3; CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT); CREATE INDEX IDX ON t1(c2);OceanBaseデータベースV4.2.0バージョンでは、Oracleモードで
CREATE TABLE AS SELECTによる並列処理を有効にするには、ALTER SESSION FORCE PARALLEL DML PARALLELを使用し、ALTER SESSION FORCE PARALLEL DDL PARALLELは使用しません。-- 並列CTASによるテーブル作成 ALTER SESSION FORCE PARALLEL DML PARALLEL 3; CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT); CREATE TABLE t2 AS SELECT * FROM t1;MySQLモードでは、構文が若干異なり、
SETステートメントを使用してSESSION変数を設定し、並列度を制御します。例:-- 並列インデックス作成 SET _FORCE_PARALLEL_DDL_DOP = 3; CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT); CREATE INDEX IDX ON t1(c2);OceanBaseデータベースV4.2.0バージョンでは、MySQLモードで
CREATE TABLE AS SELECTによる並列処理を有効にするには、SET _FORCE_PARALLEL_DML_DOPを使用し、SET _FORCE_PARALLEL_DDL_DOPは使用しません。-- 並列CTASによるテーブル作成 SET _FORCE_PARALLEL_DML_DOP = 3; CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT); CREATE TABLE t2 AS SELECT * FROM t1;
テーブルのPARALLELプロパティによる並列度の指定
DDL対象のテーブルにPARALLELプロパティが設定されている場合、以下の方法で並列DDLを有効にできます。
Oracleモードでは、
ALTER SESSIONコマンドを使用して並列を有効にします。構文は以下のとおりです:-- 並列インデックス作成 ALTER SESSION ENABLE PARALLEL DDL; CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT) PARALLEL = 3; CREATE INDEX IDX ON t1(c2) PARALLEL = 2;OceanBaseデータベースV4.2.0バージョンでは、Oracleモードで
CREATE TABLE AS SELECTを使用して並列を有効にする場合、ALTER SESSION FORCE PARALLEL DML PARALLELを使用し、ALTER SESSION FORCE PARALLEL DDL PARALLELは使用しません。-- 並列CTASテーブル作成 ALTER SESSION ENABLE PARALLEL DML; CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT) PARALLEL = 3; CREATE TABLE t2 PARALLEL 2 AS SELECT * FROM t1;MySQLモードでは、
SETステートメントを使用してセッション変数を設定することで、並列実行を有効にします。例:-- 並列インデックス作成 SET _ENABLE_PARALLEL_DDL = 1; CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT) PARALLEL = 3; CREATE INDEX IDX ON t1(c2) PARALLEL = 2;OceanBaseデータベースV4.2.0バージョンでは、MySQLモードで
CREATE TABLE AS SELECTを使用して並列を有効にする場合、SET _ENABLE_PARALLEL_DMLを使用し、SET _ENABLE_PARALLEL_DDLは使用しません。-- 並列CTASテーブル作成 SET _ENABLE_PARALLEL_DML = 1; CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT) PARALLEL = 3; CREATE TABLE t2 PARALLEL 2 AS SELECT * FROM t1;
PARALLELヒント、FORCE SESSION PARALLEL、テーブルレベルのPARALLELプロパティのうち、2つ以上を同時に指定した場合、優先順位は以下のとおりです: PARALLELヒントの優先順位 > FORCE SESSION PARALLELの優先順位 > テーブルPARALLELプロパティの優先順位
CREATE INDEXステートメントは、並列を有効にしているかどうかに関係なく、常にダイレクトライト(Direct Write、Bypass memtable)を経由します。
注意
`CREATE TABLE AS SELECT`ステートメントは現在(OceanBaseデータベースV4.2.0バージョン)ダイレクトライト機能をサポートしていません。データ量が多い場合は、まず空のテーブルを作成し、並列DMLのダイレクトロードモードを使用して並列挿入することを推奨します。
パラレルLOAD DATA
LOAD DATA の実装はパラレルDMLに基づいているわけではありません。その実装方法は、まず複数のスレッドを用いてCSVファイルを並列に分割し、複数の INSERT ステートメントに組み立て直した後、一定の並列度でこれらの INSERT ステートメントを分散して実行するというものです。
LOAD DATA /*+ parallel(2) */ infile "test.csv" INTO TABLE t1 FIELDS TERMINATED BY ',' ENCLOSED BY '"';
上記のステートメントでは、PARALLEL オプションがデータロードの並列度を指定します。PARALLEL ヒントが指定されていない場合、LOAD DATA の並列実行はデフォルトで PARALLEL を4として行われます。PARALLEL の推奨値範囲は0からテナントの最大CPU数です。
DDLの並行実行
DDLの並行実行と並列DDLの比較
前の記事で説明した並列DDLの概念は、単一のDDL操作をマルチスレッドを使用して実行速度を向上させるものであり、これらの操作自体は依然として直列処理されます。言い換えれば、マルチスレッドは単一の操作内で並行的に動作できますが、異なるDDL文は同時に実行することはできません。
一方、並列DDLは異なり、複数のDDL文が互いに独立して並行的に実行されることを許可します。この機能により、クラスタの利用率と全体的なDDL実行効率を大幅に向上させることができます。
この区別により、ユーザーは特定のシナリオでDDL操作のパフォーマンスを最適化するためにどの戦略を採用すべきかをよりよく理解できます。
並列DDLのサポート
OceanBase V4.1.0バージョンから、並列DDL実行機能が導入されました。この機能は、RootServiceノードのDDLスレッド数を拡張することで実現され、単一のDDL操作を異なる段階に分解し、特定の段階で並列処理を施します。これにより、RootServiceは自身のノード上で複数の競合のないDDLリクエストを処理でき、新規に追加されるDDLスレッド数はクラスタの規模に関連付けられています。クラスタやテナントの規模が拡大するにつれて、DDL実行のパフォーマンスも相対的に向上します。
OceanBaseデータベースで並列実行機能をサポートしているDDLは以下のとおりです:
TRUNCATE TABLE:OceanBase V4.1.0からサポート。CREATE TABLE:OceanBase V4.2.1からサポート。
使用方法と注意事項
クラスタがOceanBase V4.2.1バージョン以上でデプロイされている場合、またはV4.1.0からV4.2.1バージョン以上にアップグレードされた後は、ユーザーは追加の設定を行うことなく並列テーブル作成機能を自動的に有効にできます。
ユーザーは以下のSQLステートメントを使用して、現在のテナントのバージョン状態を確認できます。
SHOW PARAMETERS LIKE "compatible";
並列DDL操作を使用する際には、以下の点に注意する必要があります:
排他性:並列DDLと直列DDLは論理的に完全に排他的です。並列DDLの最大スループットを得るためには、クラスタが並列DDLを実行している間は他の直列DDL操作を行ってはなりません。
ノードの最適化:DDLリクエストは常にRootServiceノードで実行されます。ネットワークオーバヘッドを低減するため、RootServiceとテナントのLeaderは可能な限り同一ノード上に配置する必要があります。
リソース消費:並列DDL操作、特にテーブル作成の並列度を向上させると、システム負荷とリソース消費が増加します。
スレッド要件:システムテナントは増加したDDLリクエストに対応するために、十分なスレッドリソースが必要です。最大スループットを達成するためには、システムテナントには少なくとも6コアCPUの計算リソースが追加で必要です。
ユーザーテナントのリソース:ユーザーテナントもDDLリクエストと内部テーブルへの書き込み操作を処理するために十分なスレッドが必要です。DDLの最適なパフォーマンスを実現するためには、ユーザーテナントには少なくとも14コアCPUの計算リソースを追加で搭載する必要があります。
メモリとストレージの要件:並列DDL、特に並列テーブル作成は短期間に内部テーブルに大量のデータを書き込むため、ストレージとメモリに対する要求が高くなります。ストレージ容量が不足している場合や、メモリがデータの高速なディスクフラッシュを支えるには不十分な場合、書き込み速度が制限される可能性があります。これは並列DDLの実行効率に直接影響を及ぼすだけでなく、通常のビジネストラフィック処理のパフォーマンスにも影響します。