メインコンテンツまでスキップ
に最終更新

データの更新と削除

要約 Apache Dorisは、トランザクション対応データベースのようにSQLのUPDATEとDELETEをサポートします。ストリーミングデータロードからの部分カラムのアップサート、条件に基づく一括削除、アトミックなパーティションの入れ替えにも対応します。Unique Keyテーブルでは、Merge-on-Writeエンジンが書き込み時にrowsetごとのビットマップで削除された行を記録します。読み取り時にバージョンをマージする必要がないため、クエリのレイテンシーを低く抑えられます。バージョン2.1から、Merge-on-WriteがUnique Keyのデフォルトになりました。

Apache Dorisのデータ更新と削除:SQL UPDATE、条件付きDELETE、部分カラムのアップサート、アトミックなパーティションの入れ替えを、Unique KeyテーブルのMerge-on-Writeが支えます。

Apache Dorisでデータの更新と削除を使う理由​

Apache Dorisのデータ更新と削除は、分析エンジンにトランザクション対応の行単位の変更をもたらします。CDC、GDPRに基づく削除、個別の修正のたびにパーティションを書き換える必要はありません。多くの分析エンジンは、データウェアハウスへの書き込みは追記だけだという前提で作られました。しかし、CDCやGDPRへの対応が必要になり、本番データに誤りが生じるというありふれた現実もあります。パーティションを書き換えないと誤った行を修正できないデータウェアハウスでは、遅れて届いた修正が毎回運用作業になってしまいます。

  • Flink CDCジョブがMySQLを監視しており、すべての行更新を数秒以内に反映する必要がある。
  • ユーザーがGDPRに基づく削除を求めている。データウェアハウスからすぐに消す必要があり、「次のコンパクション後に消える」では困る。
  • 10 billion行のファクトテーブルにある一行の入力ミスが原因で、レポートの数値が誤っている。

Apache Dorisでは、このすべてにUPDATE、DELETE FROM ... WHERE、Stream Loadからの部分カラムのアップサート、一括クリーンアップに使えるTRUNCATEやアトミックなパーティションの置換といった標準のSQL機能で対応できます。テーブルが小さい必要はなく、後から書き換えジョブをスケジュールする必要もありません。

Apache Dorisのデータ更新と削除とは​

Apache Dorisのデータ更新と削除には、UPDATE SQL、条件付きDELETE、部分カラムのアップサート、パーティションの入れ替えという四つの方法があります。Unique KeyテーブルではMerge-on-Writeエンジンがこれらを支えます。行単位のUPDATE SQLはUnique Keyテーブルで使用でき、条件に基づくDELETE FROM ... WHEREはどのテーブルでも使用できます。部分カラムのアップサートはデータ取り込み時に指定し、Stream Loadのpartial_columns: trueヘッダーまたは対応するセッション変数を使います。パーティション単位の操作にはTRUNCATE PARTITIONと、一時パーティションによるアトミックな置換があります。Unique Keyモデルは内部でMerge-on-Write(MoW)を使い、削除と更新をクエリ時ではなく書き込み時に反映します。MoWはバージョン1.2で導入され、2.1でUnique Keyのデフォルトになりました。

主な用語

  • Unique Key model:プライマリキーごとに一行を保持するテーブルモデル。UPDATEとバッチアップサートに必要です。
  • Merge-on-Write (MoW):Apache Dorisは書き込み時に、新しい各キーを既存データから探し、古い行をdelete bitmapで削除対象として記録して、新しい行を新しいrowsetに書き込みます。
  • Delete bitmap:クエリが読み飛ばす行IDを記録した、rowsetごとのビットマップ。読み取り時にキーごとのバージョンをマージする代わりに使います。
  • Partial column update:一部のカラムだけを変更する書き込み。Apache Dorisは指定されなかった値を既存の行から読み取り、完全な行として書き戻します。
  • Sequence column(function_column.sequence_col):書き込みが順不同で届いたとき、同じキーのどのバージョンを採用するかをMoWに指示する、ユーザーが選ぶカラムです。
  • __DORIS_DELETE_SIGN__:どのデータロード経路からでも、値を1に設定すると行を論理削除できる隠しカラムです。

Apache Dorisのデータ更新と削除の仕組み​

Unique KeyのMoWテーブルでは、データの更新と削除は五つの段階で進みます。計画と読み取り、キーの検索、古い行のdelete bitmapの更新、新しいrowsetへの書き込み、新しいバージョンの公開です。

Unique KeyのMoWテーブルに対するUPDATEを例に説明します。

  1. 計画と読み取り。 FEがステートメントを解析し、WHERE条件を解決して、BEレプリカに読み取りを振り分けます。部分カラムの書き込みでは、BEは対象キーごとに指定されなかったカラムの値も取得します。
  2. キーの検索。 各BEはrowsetごとのメモリ内プライマリキーインデックスを参照し、対象キーが現在どのrowsetのどの行IDにあるかを調べます。
  3. 古い行の記録。 対象キーを保持する各rowsetで、該当する行IDのdelete bitmapのビットを立てます。古い行はコンパクションで回収されるまでディスクに残ります。
  4. 新しい行の書き込み。 新しい値と、部分更新のためにApache Dorisが読み取った変更されないカラムの値を、次のバージョン番号を持つ新しいrowsetに書き込みます。
  5. 公開。 トランザクションがコミットされ、新しいバージョンが見えるようになります。それ以降のクエリは、マージされたdelete bitmapに従って行を除外します。古いデータはコンパクション時に回収されます。

DELETE FROM ... WHEREは、新しい行の書き込みを除いて同じ流れで処理されます。AggregateテーブルやDuplicateテーブルでは、代わりにApache Dorisが条件をtabletのメタデータに記録し、クエリが読み取り時に適用します。

クイックスタート​

CREATE TABLE orders (
order_id BIGINT,
status VARCHAR(20),
amount DECIMAL(10, 2),
updated DATETIME
)
UNIQUE KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 4
PROPERTIES ("function_column.sequence_col" = "updated");

INSERT INTO orders VALUES
(1, 'created', 99.50, '2026-05-08 10:00:00'),
(2, 'created', 149.00, '2026-05-08 10:01:00');

UPDATE orders SET status = 'shipped', updated = NOW() WHERE order_id = 1;
DELETE FROM orders WHERE order_id = 2;

想定される結果

+----------+---------+--------+---------------------+
| order_id | status | amount | updated |
+----------+---------+--------+---------------------+
| 1 | shipped | 99.50 | 2026-05-08 11:42:31 |
+----------+---------+--------+---------------------+

注文1はその場で書き換えられ、注文2は削除されました。function_column.sequence_colプロパティは、順不同の書き込みからテーブルを保護します。updatedのタイムスタンプが古いCDCイベントは、新しい行より後に届いても、すでに存在する行より優先されません。

Apache Dorisのデータ更新と削除を使うべき場面​

Apache Dorisのデータ更新と削除は、Unique KeyテーブルへのCDCアップサート、幅の広いテーブルでの頻繁に変わるカラムの更新、GDPRに対応する行単位の削除、アトミックなバックフィルの入れ替え、複数のストリームからの幅広いテーブルの構築に適しています。一方、AggregateテーブルやDuplicateテーブルに対するUPDATE、短い間隔で繰り返す単一行の更新、プライマリキーの変更、パーティションの置換で一度に処理できる大量の行に対する条件付きDELETEには適していません。

適している用途

  • ソースのプライマリキーをApache Dorisのキーとして、Unique KeyテーブルへアップサートするFlinkやSparkのCDCパイプライン。
  • 部分カラムのStream Loadによる、幅の広いテーブルで頻繁に変わるカラム(注文ステータス、最終確認時刻、現在の残高)の更新。
  • 追記専用のDuplicateテーブルも含めた、ユーザーIDによるGDPR対応の行単位の削除。
  • ALTER TABLE ... REPLACE PARTITIONで、修正済みのパーティションをアトミックに入れ替えるバックフィル。
  • 各上流システムが担当するカラム群だけを書き込む、複数のストリームからの幅広いテーブルの構築。

適していない用途

  • AggregateテーブルやDuplicateテーブルに対するUPDATE。ステートメントは拒否されます。データ取り込みで再ロードするか(Aggregateでは値の上書きにREPLACE_IF_NOT_NULLを使います)、テーブルモデルを変更してください。
  • 短い間隔で繰り返す高頻度の単一行UPDATE。各ステートメントが独立したトランザクションになり、コミットのオーバーヘッドが支配的になります。代わりにpartial_columns: trueを指定したStream Loadで更新をまとめるか、Group Commitを使ってください。
  • プライマリキーの変更。キーを書き換える方法はありません。__DORIS_DELETE_SIGN__で古い行を論理削除し、新しい行を挿入してください。できれば同じデータロードで行います。
  • 数十億行もの一致する行を対象とする条件付きDELETE。削除ごとに記録される条件やビットマップをコンパクションで処理する必要があるため、パーティションの置換やINSERT OVERWRITEのほうが高速です。
  • Aggregateモデルでの、キー以外のカラムに基づくDELETE。条件で絞り込めるのはキーカラムだけです。このエンジンには、集約前に値カラムの条件を評価する方法がありません。

関連資料​