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ステートメントは、セッション変数を使用して並列度を指定できます。並列度を指定すると、そのセッション上のすべての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ステートメントを使用してセッション変数を設定し、並列度を制御します。例:-- 並列インデックス作成 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 ヒントが指定されていない場合、デフォルトで PARALLEL が 4 として LOAD DATA を並列実行します。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の実行効率に直接影響し、通常の業務トラフィック処理のパフォーマンスにも影響します。