OceanBaseデータベースは、以下の主要なカテゴリを含む、さまざまなステートメントのパラレル実行サポートを提供しています。
- パラレルクエリ
- 並列DML
- パラレルDDL
- 並列
LOAD DATA
パラレルクエリ
主な適用シナリオ
SELECTステートメントおよびそのサブクエリ- DMLステートメント(
INSERT/UPDATE/DELETE)のクエリ部分 - 外部テーブルクエリ
決定プロセス
パラレルクエリの実行決定には、2つの重要な側面が関係します:
パラレルクエリを実行するかどうか:
- クエリで
PARALLELヒントが使用されている場合、またはセッションでパラレルクエリが有効になっている場合、あるいはTABLEプロパティでパラレルが指定されている場合、パラレルクエリが有効になります。
- クエリで
並列度を決定する:
- ベーステーブルスキャンまたはインデックススキャンDFOの場合、その並列度は
PARALLELヒント、セッションのパラレル属性、またはTABLEプロパティによって決定されます。 - 実行時に特定のDFOがアクセスするデータがマクロブロック未満であることが検出された場合、その実行時の並列度は局所的に自動的に低下します。
JOINなどの中間ノードのDFOの並列度は、JOINの左側のサブDFOの並列度を継承します。- 一部のDFOではパラレル実行が許可されていません(例えば、
ROWNUMを計算するノードなど)。これらの並列度は強制的に1に設定されます。
- ベーステーブルスキャンまたはインデックススキャンDFOの場合、その並列度は
パラレルDML
ほとんどのシナリオにおいて、パラレルDML(Parallel DML、略称PDML)を使用することで、データのインポート、更新、削除操作のパフォーマンスを大幅に向上させることができます。
DMLの並列度
DMLの並列度は、クエリ部分の並列度と一致します。パラレルDMLを有効にすると、クエリ部分も自動的にパラレル処理が有効になります。読み取られたデータは、更新対象のテーブルのパーティション位置に基づいて再配置され、その後複数のスレッドが並列してDMLを実行します。各スレッドはいくつかのパーティションを担当します。
並列度がターゲットテーブルのパーティション数の倍数である場合、通常最適なパフォーマンスが得られます。並列度がパーティション数より大きい場合、複数のスレッドが同一パーティションのデータを処理します。並列度がパーティション数より小さい場合、単一のスレッドが複数のパーティションのデータを処理する可能性があり、各スレッドが処理するパーティションは重複しません。
- 並列度がターゲットテーブルのパーティション数より大きい場合、並列度をパーティション数の整数倍に設定することを推奨します。通常、同時に1つのパーティションにデータを挿入するスレッド数は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ステートメントの実行完了後、直ちにトランザクションをコミットする必要はなく、その後のクエリステートメントでDMLステートメントの結果を読み取ることができます。
OceanBaseデータベースV4.1.0以前のバージョンでは、パラレルDMLの実行時間が長すぎる場合、テナント構成パラメータundo_retentionに適切な値を設定する必要がありました。そうしないと、-4138 (OB_SNAPSHOT_DISCARDED)エラーが発生し、SQLが内部で繰り返し再試行され、タイムアウトするまで続く可能性があります。
undo_retentionの文字通りの意味は、アンドゥの保持ポイントです。つまり、現在の時間からどの程度遡ったアンドゥログが保持されるかということです。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;
ORA-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 ヒントを使用してパラレル処理を有効にできます。その他のDDL文では、セッション変数と TABLE PARALLEL プロパティのみがパラレル処理を有効にするためにサポートされています。
構文は以下のとおりです:
CREATE /*+ PARALLEL(3) */ INDEX IDX ON t1(c2);
SESSION変数による並列度の指定
上記のすべてのDDLステートメントは、Session変数を使用して並列度を指定できます。並列度を指定すると、その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 DDL PARALLELではなくALTER SESSION FORCE PARALLEL DML 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_DDL_DOPではなくSET _FORCE_PARALLEL_DML_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ステートメントを使用してSession変数を設定し、パラレル実行を有効にします。例:-- 並列インデックス作成 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数までです。