🛻

Tsurugiのダンプ・ロード機能

2023/12/20に公開

この記事は

Tsurugi Advent Calendar 2023の19日目(一日遅れ)です。

データを既定のフォーマットでファイルに保存したりファイルから読み込んで使用するためのダンプ・ロード機能を紹介します。

TsubakuroのAPI利用が必要(コマンドラインからは利用不可)なため少し手間がかかりますが、データを外部に保存したり外部ツールと連携するのに便利な機能です。

(2024年1月追記: BETA3リリースからArrow IPCファイル形式でのダンプやtgdumpによるコマンドラインからのダンプ実行が可能になりました https://github.com/project-tsurugi/tsurugidb/discussions/33)

ファイルフォーマット

現時点(2023年12月)ではApache Parquet形式のファイルがサポートされています(今後増える予定です)。ファイルフォーマットの詳細についてはダンプ/ロード入出力ファイル仕様を参照してください。

ダンプ

Tsubakuroからダンプを実行するAPIは下記の通りです。

com.tsurugidb.tsubakuro.sql.Transaction
FutureResponse<ResultSet> executeDump(
    PreparedStatement statement,
    Collection<? extends SqlRequest.Parameter> parameters,
    Path directory,
    SqlRequest.DumpOption option);
引数 内容
statement ダンプ処理で実行するクエリを指定します
parameters クエリのパラメーターに対する値を指定します
directory ダンプファイルの宛先ディレクトリを指定します
option ダンプファイルのサイズや失敗時の挙動などが設定できます

ダンプ処理では与えられたクエリを実行し、その結果をサーバー上のファイルに出力します。
APIはexecuteQueryと似ていますが、出力先ディレクトリdirectoryを指定する点が特徴的です。FutureResponse<ResultSet>でリザルトセットが戻りますが、これは表のデータではなく、ダンプしたファイルのパスを含みます。

リザルトセットの例

file_name
/tmp/dump/output/d1703049451_0_0.parquet
/tmp/dump/output/d1703049498_0_0.parquet
...

クエリの結果はデータ量や並列度によって適切なファイル数へ分割され指定ディレクトリへダンプされます。出力結果は順不同です。

ロード

Tsubakuroからトランザクションを使用してロードを実行するAPIは下記の通りです。

com.tsurugidb.tsubakuro.sql.Transaction
FutureResponse<ExecuteResult> executeLoad(
    PreparedStatement statement,
    Collection<? extends SqlRequest.Parameter> parameters,
    Collection<? extends Path> files);
引数 内容
statement ロード処理で実行するステートメントを指定します
parameters ステートメントのパラメーターに対する値、または入力ファイルの列名または列番号を指定します
files パラメーターの値をレコードとしてもつファイル(群)を指定します

ロード処理はファイルからレコードを読み込み、それをもとにステートメントのパラメーターに値を代入し、ステートメントの実行を行います。これを入力ファイルのレコード数だけ繰り返します。parametersにパラメーターと入力ファイルの列の対応関係を指定します(値そのもののも指定可能)。

ロード処理で使用可能なステートメントはデータ追加を行うものに限りませんが、INSERT/UPDATEやINSERT OR REPLACE(上書き挿入)やINSERT IF NOT EXISTS(存在しなければ挿入)を指定してファイルから読み出したレコードをテーブルに反映させるというのが典型的な利用法です。

例えば下記のような入力ファイル(parquetファイルは列名・型などのスキーマ情報を持ちます)があり、この内容をテーブルへ挿入したいとします。

key value
1 100
2 200
... ...

(簡単のために値はINTの範囲に収まる整数値とします)

ロード対象のテーブルをDDLで作成します。

CREATE TABLE T (C0 INT NOT NULL PRIMARY KEY, C1 INT)

下記のようにステートメントのprepareを行いexecuteLoadを実行します。

var prep = client.prepare(
    "INSERT OR REPLACE INTO T VALUES(:p0, :p1)",
    Placeholders.of("p0", int.class),
    Placeholders.of("p1", int.class)).await();
Transaction tx = client.createTransaction().await()
var result = tx.executeLoad(
    prep,
    List.of(
        Parameters.referenceColumn("p0", "key"),
        Parameters.referenceColumn("p1", "value")
    ),
    Path.of("/path/to/input/file")
    ).await();
var status = tx.commit().await();

parametersでArrowファイルにおける列名(フィールド番号も可能)を指定することでファイルの列とステートメントのパラメーターの対応が指定されます。

トランザクショナルロードとノントランザクショナルロード

上記はユーザーが指定したトランザクション内でステートメントを実行するもの(トランザクショナルロード)でした。これに対してTsurugi内部で必要なトランザクションを自動的に開始してロードを実行し、終了時にコミットまでを行う機能もあります(ノントランザクショナルロード)。

トランザクショナルロードcom.tsurugidb.tsubakuro.sql.Transactionのメソッドでしたが、ノントランザクショナルロードは特定のトランザクションに関連しないためcom.tsurugidb.tsubakuro.sql.SqlClientのメソッドとして提供されています。引数は共通です。

com.tsurugidb.tsubakuro.sql.SqlClient
FutureResponse<ExecuteResult> executeLoad(
    PreparedStatement statement,
    Collection<? extends SqlRequest.Parameter> parameters,
    Collection<? extends Path> files);

ノントランザクショナルロードのメリットとデメリットは下記の通りです。

メリット
必要に応じて複数トランザクションへ並列化されるので性能向上が見込める
トランザクショナルロードでは files へ複数ファイルが指定されてもトランザクションは1つなので逐次実行されます。ノントランザクショナルロードではこの制約がないため複数ファイルが同時並列にロード可能です。

デメリット
一連のロード処理が複数トランザクションへ分割されるのでエラー発生時にデータの一貫性が保たれない可能性がある
例えばエラー発生時、そこまででコミット済みのトランザクションの内容がロード対象のテーブルに残ることがあります。

制約

ダンプ・ロード機能はサーバー上に配置されるファイルを経由するため、ユーザーやアプリケーションプログラムがアクセス可能なディレクトリがサーバー上にある必要があります。

Discussion