OceanBaseのパーティション交換機能とダイレクトロード技術を組み合わせることで、大規模な増分データのロードに対する効率的なソリューションを提供します。フルダイレクトロードにより、データを一括して新規作成された非パーティションテーブルに高速にロードし、その後パーティション交換を用いてデータを目標のパーティションテーブルへ原子的に移行することで、既存のパーティションテーブルへの増分データインポート性能を向上させます。
パーティション交換とフルダイレクトロードを組み合わせる理由
ビッグデータのシナリオでは、企業はしばしば膨大な増分データの迅速なインポート要件に直面します。従来のデータインポート方法にはパフォーマンスのボトルネックがありますが、パーティション交換とダイレクトロードを組み合わせたソリューションは、インポート効率とクエリパフォーマンスの両方を兼ね備えています。
フルダイレクトロードと増分ダイレクトロードの利点比較
増分ダイレクトロードの特徴と制限
- データストレージ形式: 増分ダイレクトロードでは、ダンプファイルが生成され、これらのダンプファイルはデフォルトで行ストア形式を採用します。
- パフォーマンスへの影響: カラムストアシナリオでは、行ストア形式のダンプファイルはクエリパフォーマンスを著しく低下させます。
- 適用シナリオ: 小規模で頻繁なデータ更新シナリオに適しています。
フルダイレクトロードの特徴と利点
- データストレージ形式: フルダイレクトロードはすべてのデータを書き直し、生成されたデータファイルはカラムストア形式を採用します(テーブルがカラムストアに設定されている場合)。
- パフォーマンスの利点: すべてのデータがベースラインデータであるため、クエリパフォーマンスが最適です。
- 適用シナリオ: 大規模データの一括インポートに適しています。
フルダイレクトロードとパーティション交換の利点
フルダイレクトロードとパーティション交換技術を組み合わせることで、増分インポートにおけるダンプ形式で保存されるデータのパフォーマンスボトルネック問題を効果的に解決できます。このソリューションの核心的な利点は以下の通りです:
データ形式の最適化: 増分データをベースラインデータ形式に変換し、すべてのデータをカラムストア形式で保存することを保証し、行ストアのダンプファイルがクエリパフォーマンスに与える悪影響を排除します。
パフォーマンス向上:
- クエリパフォーマンス:すべてのデータが統一されたベースライン形式になるため、最適なクエリパフォーマンスを実現します。
- インポートパフォーマンス:ダイレクトロードの効率的なメカニズムを活用し、データロード速度を大幅に向上させます。
アーキテクチャの統一性: パーティション交換メカニズムを通じて、増分データと既存データの形式を統一し、混合ストレージ形式によるパフォーマンス損失を回避します。
この技術ソリューションは、増分インポートの柔軟性を維持しつつ、フルインポートのパフォーマンス利点を得ており、大規模データ処理シナリオで最高のパフォーマンスを提供します。
シナリオ分析
空のテーブルの初期化
状況: ターゲットテーブルは空で、初期データをインポートする必要があります。
- 推奨ソリューション: 直接にフルダイレクトロードを使用する
- 利点: すべてのデータがカラムストアのベースラインであるため、クエリパフォーマンスが最適です。
既存データの増分インポート
状況: ターゲットテーブルに履歴データがあり、新しい増分データをインポートする必要があります。
従来の増分ダイレクトロード
- 利点: インポート速度が速く、既存データに影響を与えません。
- 欠点: 新しくインポートされたデータは行ストアのダンプファイルであり、クエリパフォーマンスが低いです。
従来のフルダイレクトロード
- 利点: すべてのデータがカラムストアに書き直されるため、クエリパフォーマンスが最適です。
- 欠点: 全ての履歴データを書き直す必要があるため、インポート時間が長く、リソース消費が大きいです。
フルダイレクトロード + パーティション交換(推奨ソリューション)
利点:
- 新規データはフルダイレクトロードによりカラムストアのベースラインが生成され、クエリパフォーマンスが最適です
- 増分データのみをインポートするため、履歴データに影響しません
- パーティション交換操作は原子的で、業務の中断がありません
- インポートパフォーマンスとクエリパフォーマンスの両方が最適化されています
パフォーマンス比較の簡易例
顧客が1TBの注文テーブルを持ち、毎日100GBのデータが追加される場合を想定します:
従来の増分ダイレクトロード
- 履歴データ:1TB(カラムストア、クエリは高速)
- 新規データ:100GB(行ストアのダンプ、クエリは低速)
- クエリパフォーマンス:混合ストレージ形式で、全体のパフォーマンスが低下します
従来のフルダイレクトロード
- データの書き直し:1.1TB(すべてカラムストア、クエリは高速)
- インポート時間:1TBの履歴データと100GBの新規データを書き直す必要があるため、時間がかかります
- リソース消費:高い
フルダイレクトロード + パーティション交換
- 履歴データ:1TB(カラムストア、変更なし)
- 新規データ:100GB(カラムストアのベースライン、クエリは高速)
- インポート時間:100GBの新規データのみをインポートする必要があるため、時間がかからない
- クエリパフォーマンス:すべてカラムストアで、パフォーマンスが最適です
パーティション交換の基本構文
基本パーティション交換構文
ALTER TABLE target_partition_table_name
EXCHANGE PARTITION first_level_partition_name
WITH TABLE origin_partition_table_name
WITHOUT VALIDATION;
インデックスを含むパーティション交換構文
ALTER TABLE target_partition_table_name
EXCHANGE PARTITION first_level_partition_name
WITH TABLE origin_partition_table_name
INCLUDING INDEXES
WITHOUT VALIDATION;
使用上の制限
target_partition_table_nameはサブパーティションテーブルでなければならず、交換するパーティションはそのテーブルのいずれかのパーティション名である必要があります。origin_partition_table_nameはパーティションテーブルでなければならず、そのパーティションタイプは交換に使用されるパーティションの下のサブパーティションと完全に一致している必要があります。- ターゲットテーブルのパーティションタイプは
RANGE (COLUMNS)またはLIST (COLUMNS)でなければなりません。 - パーティションとサブパーティションを交換した後、関連するテーブルの統計情報は無効になり、再収集する必要があります。
ダイレクトロードとパーティション交換の例(パーティション1に基づく)
- データの高速読み込み: ダイレクトロード技術はSQLやMemtableを直接バイパスし、大量データを秒単位で読み込みます。
- 業務への影響ゼロ: パーティション交換操作はバックグラウンドで原子的に実行されるため、業務クエリにおけるロックテーブルの影響はありません。
- パーティションレベルのデータ管理: パーティション交換により、データ移行範囲を正確に制御でき、時間/範囲によるパーティショニングの柔軟な戦略をサポートします。
具体的な操作手順は以下の通りです:
- パーティションテーブルA に 空の新しいパーティションP を作成します。
- テーブルAと構造が完全に同じ 非パーティションテーブルB を新規作成し、フルダイレクトロードによってデータをテーブルBにインポートします。
- パーティション交換機能を利用して、テーブルAの新しいパーティションPとテーブルBを交換します。
ステップ1:ターゲットパーティションテーブル(注文テーブル orders)を作成する
注文テーブル orders が order_date フィールドに基づいて範囲パーティション化されており、データ交換用の空パーティション p_new が予約されていることを仮定します。
-- パーティションテーブルAを作成する(例:注文テーブル)
CREATE TABLE orders (
order_id BIGINT,
order_date TIMESTAMP NOT NULL,
customer_id INT,
amount DECIMAL(10,2),
product_id INT
)
PARTITION BY RANGE COLUMNS(order_date) (
PARTITION p_old1 VALUES LESS THAN ('2023-01-01'),
PARTITION p_old2 VALUES LESS THAN ('2023-04-01'),
-- 新しい空パーティションp_newを追加し、後のデータ交換に使用する
PARTITION p_new VALUES LESS THAN ('2023-07-01')
);
ステップ2:増分データを準備し、非パーティションテーブルを作成する
増分データファイルを作成またはダウンロードします。
増分データファイルを
orders_increment.csvと仮定し、以下のフィールドを含みます:order_id,order_date,customer_id,amount,product_id 1001,"2023-05-01",101,199.99,1001 1002,"2023-06-15",102,299.99,1002 1003,"2023-05-10",103,350.00,1003 1004,"2023-05-20",104,49.99,1004 1005,"2023-06-01",105,450.50,1005 1006,"2023-05-25",106,200.00,1006 1007,"2023-06-10",107,150.75,1007 1008,"2023-05-15",108,300.00,1008 1009,"2023-06-20",109,499.99,1009 1010,"2023-05-30",101,99.99,1010非パーティションテーブル
orders_bypassを作成します。ターゲットパーティションテーブル(注文テーブル orders)と構造が完全に同じ非パーティションテーブル
orders_bypassを作成します:CREATE TABLE orders_bypass ( order_id BIGINT, order_date TIMESTAMP NOT NULL, customer_id INT, amount DECIMAL(10,2), product_id INT ); -- 一時テーブルを作成 CREATE TABLE temp_staging_table LIKE orders_bypass;
ステップ3:非パーティションテーブル orders_bypass へのデータのダイレクトロード
フルダイレクトロードを使用して、非パーティションテーブル orders_bypass にデータを迅速にインポートします。
-- 例です。実際には、OceanBaseのObLoaderなどのツールを使用する必要があります。
-- LOAD DATAまたはINSERT /*+ APPEND */ を使用してデータをインポートします。
LOAD DATA /*+ APPEND */ INFILE '/tmp/orders_increment.csv'
INTO TABLE temp_staging_table
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
-- またはINSERTを使用して一括インポートする(APPENDヒントが必要)
INSERT /*+ APPEND */ INTO orders_bypass
SELECT * FROM temp_staging_table; -- 一時テーブルはorders_bypassと構造が一致している必要があります。
ステップ4:パーティション交換(Exchange Partition)を実行する
非パーティションテーブル orders_bypass のデータと、パーティション対象のパーティションテーブル(注文テーブル orders)の空パーティション p_new を交換します。
-- パーティション交換を実行する
ALTER TABLE orders
EXCHANGE PARTITION p_new
WITH TABLE orders_bypass
WITHOUT VALIDATION; -- オプション:テーブルBにインデックスが含まれる場合は、同期的に交換する必要があります。
ステップ5:データ交換結果を検証する
-- パーティションp_newのデータを検証する
SELECT COUNT(*) FROM orders PARTITION (p_new);
-- テーブルorders_bypassが空であるかどうかを検証する(交換後、テーブルorders_bypassのデータはクリアされます)
SELECT COUNT(*) FROM orders_bypass;
実行結果の例:
MySQL [test_db]> SELECT COUNT(*) FROM orders PARTITION (p_new);
+----------+
| COUNT(*) |
+----------+
| 10 |
+----------+
1 row in set (0.04 sec)
MySQL [test_db]> SELECT COUNT(*) FROM orders_bypass;
+----------+
| COUNT(*) |
+----------+
| 0 |
+----------+
1 row in set (0.01 sec)
ステップ6:データのクリーンアップとその後の操作
-- オプション:空のテーブルorders_bypassを削除する
DROP TABLE orders_bypass;
-- オプション:パーティションp_newをより明確な名前に変更する
ALTER TABLE orders RENAME PARTITION p_new TO p_2023q2;
ダイレクトロードとパーティション交換の例(サブパーティションを基に)
- データの高速ロード: ダイレクトロード技術はSQLやMemtableを直接バイパスし、大量データを秒単位でロードします。
- 業務への影響ゼロ: パーティション交換操作はバックグラウンドで原子的に完了し、業務クエリにおけるロックテーブルの影響がありません。
- パーティションレベルのデータ管理: パーティション交換により、データ移行範囲を精密に制御でき、時間/範囲パーティションに対する柔軟な戦略をサポートします。
- サブパーティションテーブルの増分データインポート: パーティションがRANGE/LIST、サブパーティションがHASHの複合パーティションテーブルシナリオに適用されます。
具体的な操作手順は以下の通りです:
- サブパーティションテーブルA(パーティションRANGE/LIST + サブパーティションHASH)に、空の新しいパーティションPを作成します。
- 新しいパーティションHASHテーブルBを作成します。そのパーティションタイプはテーブルAのサブパーティションと完全に一致している必要があり、フルダイレクトロードを使用してデータをテーブルBにインポートします。
- パーティション交換機能を利用して、テーブルAの新しいパーティションPとテーブルBを交換します。
ステップ1:ターゲットのサブパーティションテーブル(注文テーブルorders)を作成する
注文テーブル orders が order_date フィールドでパーティション範囲分割され、さらに order_id でハッシュ分割されていると仮定します。また、データ交換用に空のパーティション p_new を1つ予約します。
-- サブパーティションテーブルAを作成する(例:注文テーブル)
CREATE TABLE orders (
order_id BIGINT,
order_date TIMESTAMP NOT NULL,
customer_id INT,
amount DECIMAL(10,2),
product_id INT,
PRIMARY KEY (order_id, order_date)
)
PARTITION BY RANGE COLUMNS(order_date)
SUBPARTITION BY HASH(order_id) SUBPARTITIONS 5
(
PARTITION p_old1 VALUES LESS THAN ('2023-01-01'),
PARTITION p_old2 VALUES LESS THAN ('2023-04-01'),
-- 新規に空のパーティションp_newを追加し、後のデータ交換に使用する
PARTITION p_new VALUES LESS THAN ('2023-07-01')
);
ステップ2:増分データを準備し、パーティションハッシュテーブルを作成する
増分データファイルを作成またはダウンロードします。
増分データファイルを
orders_increment.csvと仮定します。このファイルには以下のフィールドが含まれます:order_id,order_date,customer_id,amount,product_id 1001,"2023-05-01",101,199.99,1001 1002,"2023-06-15",102,299.99,1002 1003,"2023-05-10",103,350.00,1003 1004,"2023-05-20",104,49.99,1004 1005,"2023-06-01",105,450.50,1005 1006,"2023-05-25",106,200.00,1006 1007,"2023-06-10",107,150.75,1007 1008,"2023-05-15",108,300.00,1008 1009,"2023-06-20",109,499.99,1009 1010,"2023-05-30",101,99.99,1010パーティションハッシュテーブル
orders_bypassを作成します。ターゲットのサブパーティションテーブル(注文テーブル
orders)と同じ構造を持つパーティションハッシュテーブルorders_bypassを作成します。パーティションタイプはターゲットテーブルのサブパーティションと完全に一致している必要があります(つまり、ハッシュ分割である必要があります)。-- パーティションハッシュテーブルBを作成します。パーティション数はターゲットテーブルのサブパーティション数と一致させる必要があります(5個) CREATE TABLE orders_bypass ( order_id BIGINT, order_date TIMESTAMP NOT NULL, customer_id INT, amount DECIMAL(10,2), product_id INT, PRIMARY KEY (order_id, order_date) ) PARTITION BY HASH(order_id) PARTITIONS 5;
注意
パーティションハッシュテーブル orders_bypass のパーティションタイプは、ターゲットのサブパーティションテーブル orders のサブパーティションと完全に一致している必要があります。つまり、ターゲットテーブルのサブパーティションが SUBPARTITION BY HASH(order_id) の場合、ソーステーブルは PARTITION BY HASH(order_id) でなければなりません。
ステップ3:データをパイプラインで直接ロードして、パーティション1次ハッシュテーブルorders_bypassにインポートする
全量のダイレクトロードを使用して、パーティション1次ハッシュテーブルorders_bypassにデータを迅速にインポートします。
-- データロード用の一時テーブルを作成
CREATE TABLE temp_staging_table LIKE orders_bypass;
-- LOAD DATAを使用したダイレクトロード
LOAD DATA /*+ APPEND */ INFILE '/tmp/orders_increment.csv'
INTO TABLE temp_staging_table
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
-- INSERTを使用した一括インポート(APPENDヒントを組み合わせてダイレクトロードを実現)
INSERT /*+ APPEND */ INTO orders_bypass
SELECT * FROM temp_staging_table;
-- 一時テーブルを削除
DROP TABLE temp_staging_table;
説明
実際の運用では、OceanBaseのObLoaderなどのツールと組み合わせてダイレクトロードを行うことで、より効率的なデータロードが可能です。
ステップ4:パーティション交換(Exchange Partition)を実行する
パーティション1次ハッシュテーブルorders_bypassのデータと、ターゲットのサブパーティションテーブル(注文テーブルorders)の空のパーティションp_newとを交換します。
-- パーティション交換を実行する
ALTER TABLE orders
EXCHANGE PARTITION p_new
WITH TABLE orders_bypass
WITHOUT VALIDATION;
注意
パーティション交換が成功すると、テーブルorders_bypassのデータはクリアされ、元のデータはターゲットパーティションp_newに交換されます。ソーステーブルにインデックスが含まれる場合は、INCLUDING INDEXESオプションを使用してインデックスも同期して交換できます。
ステップ5:データ交換結果を検証する
パーティション交換が成功したかどうかを検証します。
-- パーティションp_newのデータを検証する
SELECT COUNT(*) FROM orders PARTITION (p_new);
-- テーブルorders_bypassが空かどうかを検証する(交換後、テーブルorders_bypassのデータはクリアされる)
SELECT COUNT(*) FROM orders_bypass;
検証結果の例:
MySQL [test_db]> SELECT COUNT(*) FROM orders PARTITION (p_new);
+----------+
| COUNT(*) |
+----------+
| 10 |
+----------+
1 row in set
MySQL [test_db]> SELECT COUNT(*) FROM orders_bypass;
+----------+
| COUNT(*) |
+----------+
| 0 |
+----------+
1 row in set
ステップ6:データのクリーンアップとその後の操作
データ交換が完了したら、以下のクリーンアップとその後の操作を実行できます。
-- オプション:不要になった場合は、空のテーブルorders_bypassを削除する
DROP TABLE orders_bypass;
-- オプション:パーティションp_newをより明確な名前にリネームする
ALTER TABLE orders RENAME PARTITION p_new TO p_2023q2;
-- 統計情報を再収集する(交換後、統計情報は無効になる)
ANALYZE TABLE orders;
サポートされていないユースケース
以下のシナリオでは、パーティション交換はサポートされていません:
- パーティション1次テーブルとパーティション1次テーブルの交換:サポートされていません。
- サブパーティションテーブルとサブパーティションテーブルの交換:サポートされていません。
- サブパーティションテーブルのパーティション1次がハッシュパーティションの場合:サポートされていません。ターゲットテーブルのパーティション1次はrangeまたはlistタイプである必要があります。