本記事では、並列インポートとデータ圧縮に関する使用方法と説明を紹介します。
一般的なユースケースは以下の通りです:
データ移行:大量のデータをあるシステムから別のシステムに移行する必要がある場合、並列インポートを使用することでデータ移行の速度を大幅に向上させることができます。また、データ圧縮により、必要な転送帯域幅とストレージリソースを削減できます。
バックアップとリストア:データバックアップ時にデータ圧縮を採用することで、バックアップファイルのサイズを縮小し、ストレージ容量を節約できます。データ復元時に並列インポートを採用することで、データ復元の速度を向上させることができます。
カラムストアテーブル:カラムストアテーブルでクエリを実行する際、通常はクエリに関連する列にのみアクセスする必要があり、行全体のデータにアクセスする必要はありません。したがって、圧縮された列はそのままスキャンや処理が可能であり、これによりI/O操作が削減され、クエリ速度が向上し、全体的なクエリパフォーマンスが高まります。カラムストアテーブルの場合、データを一括インポートした後にデータ圧縮を行うと、読み取りパフォーマンスが向上します。ただし、カラムストアテーブルのメジャーコンパクション速度は遅くなる可能性があるため注意が必要です。
パラレルインポート
分析クエリに加えて、Operational OLAPにおいて非常に重要な部分が大量データのパラレルインポート、すなわちデータバッチ処理能力です。OceanBaseデータベースのパラレル実行フレームワークは、DMLステートメントも並列的に実行することができます(Parallel DML)。これにより、マルチノードデータベースにおいて複数マシンへの同時書き込みを実現し、大規模トランザクションの一貫性を保証します。非同期ダンプメカニズムと組み合わせることで、メモリが逼迫した状況下でもLSM-Treeストレージエンジンの大規模トランザクション対応を大幅に最適化できます。
PDMLを体験する例を挙げます。引き続きTPC-Hのlineitemテーブルを基に、同じテーブル構造の空のテーブルlineitem2を作成します。次にINSERT INTO ...SELECTを用いた1つのSQLステートメントで、lineitemの全600万行のデータを新しいテーブルlineitem2に挿入します。以下では、PDMLを無効にした場合と有効にした場合で実行し、その効果と違いを観察します。
まず、lineitemのテーブル構造をコピーしてlineitem2を作成します。注意点として、OceanBaseデータベースではパーティションテーブルを用いてデータ拡張を行います。この例では16個のパーティションを使用しているため、対応するlineitem2も完全に同一である必要があります:
obclient [test]> SHOW CREATE TABLE lineitem\G
*************************** 1. row ***************************
Table: lineitem
Create Table: CREATE TABLE `lineitem` (
`l_orderkey` bigint(20) NOT NULL,
`l_partkey` bigint(20) NOT NULL,
`l_suppkey` bigint(20) NOT NULL,
`l_linenumber` bigint(20) NOT NULL,
`l_quantity` bigint(20) NOT NULL,
`l_extendedprice` bigint(20) NOT NULL,
`l_discount` bigint(20) NOT NULL,
`l_tax` bigint(20) NOT NULL,
`l_returnflag` char(1) DEFAULT NULL,
`l_linestatus` char(1) DEFAULT NULL,
`l_shipdate` date NOT NULL,
`l_commitdate` date DEFAULT NULL,
`l_receiptdate` date DEFAULT NULL,
`l_shipinstruct` char(25) DEFAULT NULL,
`l_shipmode` char(10) DEFAULT NULL,
`l_comment` varchar(44) DEFAULT NULL,
PRIMARY KEY (`l_orderkey`, `l_linenumber`),
KEY `I_L_ORDERKEY` (`l_orderkey`) BLOCK_SIZE 16384 LOCAL,
KEY `I_L_SHIPDATE` (`l_shipdate`) BLOCK_SIZE 16384 LOCAL
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = COMPACT COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 1 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0 TABLEGROUP = 'x_tpch_tg_lineitem_order_group'
partition by key(l_orderkey)
(partition p0,
partition p1,
partition p2,
partition p3,
partition p4,
partition p5,
partition p6,
partition p7,
partition p8,
partition p9,
partition p10,
partition p11,
partition p12,
partition p13,
partition p14,
partition p15)
1 row in set
デフォルトモードで実行し、PDMLを有効化しない
lineitem2 を作成した後、まずはデフォルト設定で並列処理を有効にせずに挿入します。これは600万行の大規模トランザクションであるため、OceanBaseデータベースのデフォルトのトランザクションタイムアウト時間をより大きな値(単位:μs)に調整する必要があります。
# SET ob_query_timeout = 1000000000;
# SET ob_trx_timeout = 1000000000;
データを挿入した結果は次のとおりです:
obclient [test]> INSERT INTO lineitem2 SELECT * FROM lineitem;
Query OK, 6001215 rows affected (1 min 47.312 sec)
Records: 6001215 Duplicates: 0 Warnings: 0
並列処理を有効にしない場合、単一トランザクションで600万行のデータを挿入するのに、OceanBaseは107秒かかりました。
PDMLを有効にして実行する
次に、Hintを追加してPDMLの実行オプションを有効にします。再度挿入する前に、前回挿入したデータをクリアします。
obclient [test]> TRUNCATE TABLE lineitem2;
obclient [test]> INSERT /*+ parallel(16) enable_parallel_dml */ INTO lineitem2 SELECT * FROM lineitem;
今回の実行時間を見てみましょう:
obclient> TRUNCATE TABLE lineitem2;
Query OK, 0 rows affected (0.108 sec)
obclient> INSERT /*+ parallel(16) enable_parallel_dml */ INTO lineitem2 SELECT * FROM lineitem;
Query OK, 6001215 rows affected (22.117 sec)
Records: 6001215 Duplicates: 0 Warnings: 0
PDMLを有効にした後、同じテーブルに600万行のデータを挿入するのに、OceanBaseデータベースの所要時間は約22秒に短縮されました。PDML機能によるパフォーマンス向上は約5倍です。この機能は、ユーザーがバッチデータ処理を必要とするシナリオで役立ちます。
データ圧縮
OceanBaseデータベースは、LSM-Tree構造に基づいて独自のストレージエンジンを開発しました。データは大まかにベースラインデータ(SSTable)と増分データ(MemTable)の2つに分類されます。ベースラインデータはディスクに保存され、増分変更はメモリ上で行われます。これにより、データをディスク上でよりコンパクトな方法で格納できる一方で、ディスク上のベースラインデータは頻繁に更新されない特性を活かし、OceanBaseデータベースでは汎用圧縮アルゴリズムを用いてベースラインデータをさらに圧縮しています。その結果、非常に高いデータ圧縮率を実現しています。しかも、このデータ圧縮はクエリや書き込みのパフォーマンスを損なうことはありません。以下では、OceanBaseデータベースに大量の外部データをインポートし、データ圧縮率を確認する方法を紹介します。
データの準備
まず、データ準備ツールCreateData.jarを使用して、5000万行のテストデータを/home/softディレクトリに生成します。データ生成には約10~20分かかりますが、他のツールを使用してテストデータを作成することも可能です。
#mkdir /home/soft/
#java -jar CreateData.jar /home/soft/ 50000000
filePath is : /home/soft/
Start Time : 2022-07-10 15:33:00
End Time : 2022-07-10 15:52:53
#du -sh *
10G t_bigdata_loader.unl
OceanBaseデータベースでは、CSV形式のデータをインポートする複数の方法をサポートしています。本記事では、Load Dataコマンドを実行する方法について説明します。
まず、生成されたファイルに名前を付け、実際のサイズを確認します。
# mv t_bigdata_loader.unl t_f1.csv # du -sh t_f1.csv 10G t_f1.csvt_f1.csvファイルの内容を確認すると、事前に生成されたCSVファイルには、ランダムアルゴリズムで取得した8列のデータが含まれており、それぞれ異なるデータ型に対応しています。そのため、OceanBaseのデータ圧縮機能を試すには、まずテナント内にテーブルを作成し、このCSVファイルのデータをインポートする必要があります。1|1896404182|1980-06-01|2004-10-25 13:30:39|7470.689|33062564.9527|nOLqnBYtnp|BzWYjZjeodtBNzXSMyBduMNzwDPSiVmhVgPJMeEkeAwKBCorzblwovIHDKBsQhbVjQnIdoeTsiLXTNwyuAcuneuNaol| 2|572083440|2018-11-09|1998-07-11 01:23:28|6891.054|66028434.4013|UzqteeMaHP|vQWbWBXEWgUqUTzqsOSciiOuvWVcZSrlEOQDwDVGmvGRQYWmhCFdEkpsUsqrWEpKtmxSwURHIHxvmlXHUIxmfelYboeGEuScKKqzpuNLryFsStaFTTRqSsVlCngFFjHnEnpaCnWsdwztbiHJyoGkaxrFmyPAmVregfydArrUZsgRqBpQ| 3|1139841892|2006-10-07|1999-06-26 17:02:22|286.43692|51306547.5055|KJJtylgxkv|BuBdFTBIIFsEPVxsVBRqAnFXSBdtZDgfumUhIx| 4|1777342512|1982-12-18|2017-11-19 07:56:35|2986.242|85860387.8696|rTkUBWhdPt|JSazOTAmvtCBrINttDwublNJNRFDIiWkHtWZXmWgKHoZCKGqmmETkIcYLXiSgKkoaATNgjvPxVGjeCOODLEWqrQHqowbMjOLOKrtirWEOpUSxiUudZduTCUvZElKzZfggvCBNthwzKJc| ....testテナントのtestデータベースに、t_f1という名前のテーブルを作成します。テナントの作成手順の詳細については、テナント管理の内容を参照してください。# obclient -hxxx.xxx.xxx.xxx -P2881 -uroot@test -Dtest -A -p -c obclient [test]> CREATE TABLE t_f1(id DECIMAL(10,0),id2 DECIMAL(10,0),id3 DATE,id4 DATE,id5 FLOAT,id6 FLOAT,id7 VARCHAR(30),id8 VARCHAR(300));
データのインポート
OceanBaseデータベースに組み込まれているLoad Dataコマンドを使用してデータをインポートできます。Load Dataも並列インポートをサポートしています。インポートを開始する前に、以下の設定を行います。Load Dataコマンドは、データファイルがOBServerノード上でローカル実行される場合にのみサポートされます。リモートからのデータインポートを希望する場合は、OceanBaseデータベースのobloaderツールを参照してください。
obclient [test]> SET GLOBAL secure_file_priv = "/";
obclient [test]> GRANT FILE ON *.* to username;
注意
セキュリティ上の理由により、secure_file_priv を変更するSQLステートメントは、ローカル接続されたクライアントからのみ実行できます。詳細については、secure_file_privを参照してください。
設定完了後、セッションを再接続して設定を有効にします。その後、セッションのトランザクションタイムアウト時間を設定し、実行中にタイムアウトで終了しないようにします。
obclient [test]> SET ob_query_timeout=1000000000;
obclient [test]> SET ob_trx_timeout=1000000000;
次に、インポートステートメントを実行します:
obclient [test]> LOAD DATA /*+ parallel(16) */ INFILE '/home/soft/t_f1.csv' INTO table t_f1 fields TERMINATED BY '\|' LINES TERMINATED BY '\n';
ご覧のように、並列インポートを有効にすると、10GBのデータをインポートするのに約4分かかりました。本記事では、テナントのCPU並列度を16に設定していますが、お使いの環境に応じて適切な並列度を設定できます。設定値が高いほど、インポート速度は向上します。
インポート後、データベースにログインして、対象テーブルのレコード数と使用容量を確認します。
テーブルのレコード数は5000万件です。
obclient [test]> SELECT COUNT(*) FROM t_f1; +----------+ | count(*) | +----------+ | 50000000 | +----------+データベースのメジャーコンパクションを実行します。
ベースラインデータの圧縮効果を確認するために、
rootユーザーでクラスタのsysテナントにログインし、データベースのメジャーコンパクションを手動でトリガーします。これにより、増分データとベースラインデータが統合・圧縮されます。以下の方法で手動でメジャーコンパクションをトリガーできます。# obclient -h127.0.0.1 -P2881 -uroot@sys -Doceanbase -A -p -c obclient[oceanbase]> ALTER SYSTEM MAJOR FREEZE;以下のクエリがIDLEを返したら、メジャーコンパクションが完了したことを示します。
obclient [oceanbase]> SELECT * FROM oceanbase.CDB_OB_MAJOR_COMPACTION; +-----------+---------------------+----------------------------+----------------------+---------------------+----------------------------+----------------------------+--------+----------+--------------+------+ | TENANT_ID | FROZEN_SCN | FROZEN_TIME | GLOBAL_BROADCAST_SCN | LAST_SCN | LAST_FINISH_TIME | START_TIME | STATUS | IS_ERROR | IS_SUSPENDED | INFO | +-----------+---------------------+----------------------------+----------------------+---------------------+----------------------------+----------------------------+--------+----------+--------------+------+ | 1 | 1679248800404017149 | 2023-03-20 02:00:00.404017 | 1679248800404017149 | 1679248800404017149 | 2023-03-20 02:00:44.035785 | 2023-03-20 02:00:00.442481 | IDLE | NO | NO | | | 1001 | 1679248804191204504 | 2023-03-20 02:00:04.191205 | 1679248804191204504 | 1679248804191204504 | 2023-03-20 02:00:46.094551 | 2023-03-20 02:00:04.218608 | IDLE | NO | NO | | | 1002 | 1679248802450394471 | 2023-03-20 02:00:02.450394 | 1679248802450394471 | 1679248802450394471 | 2023-03-20 02:00:33.818514 | 2023-03-20 02:00:02.484814 | IDLE | NO | NO | | 1 row in setsysテナントで以下のステートメントを実行すると、OceanBaseにインポートされたデータのストレージ使用状況を確認できます。
obclient [oceanbase]> select b.table_name,a.svr_ip,data_size/1024/1024/1024 from CDB_OB_TABLET_REPLICAS a,CDB_OB_TABLE_LOCATIONS b where a.tablet_id=b.tablet_id and b.table_name='T_F1'; +------------+---------------+----------------------------+ | table_name | svr_ip | a.data_size/1024/1024/1024 | +------------+---------------+----------------------------+ | t_f1 | xxx.xx.xxx.xx | 6.144531250000 | +------------+---------------+----------------------------+
圧縮後のテーブルサイズは約6.145GBで、圧縮率は10/6.145 = 1.62です。