メインコンテンツまでスキップ
バージョン: 26.x

データ更新概要

今日のデータ駆動型意思決定の環境において、データの「フレッシュネス」は、企業が激しい市場競争の中で差別化を図るための中核的な競争優位性となっています。従来のT+1データ処理モデルは、その固有のレイテンシのため、現代のビジネスの厳格なリアルタイム要件を満たすことができなくなっています。ビジネスデータベースとデータウェアハウス間のミリ秒レベルの同期の実現、運用戦略の動的調整、または決定精度を確保するための数秒以内でのエラーデータの修正など、堅牢なリアルタイムデータ更新機能が重要です。

Apache Dorisは、モダンなリアルタイム分析データベースとして、究極のデータフレッシュネスを提供することをその中核的な設計目標の一つとしています。強力なデータモデルと柔軟な更新メカニズムを通じて、データ分析のレイテンシを日レベルや時間レベルから秒レベルに圧縮することに成功し、ユーザーがリアルタイムで迅速なビジネス意思決定ループを構築するための堅固な基盤を提供しています。

この文書は、Apache Dorisのデータ更新機能を体系的に説明する公式ガイドとして機能し、その中核原理、多様な更新・削除方法、典型的なアプリケーションシナリオ、および異なるデプロイメントモードでのパフォーマンスベストプラクティスをカバーし、Dorisのデータ更新機能を包括的に習得し効率的に活用できるよう支援することを目的としています。

1. 中核概念:Tableモデルと更新メカニズム

Dorisにおいて、データTableのData Modelは、そのデータ構成と更新動作を決定します。異なるビジネスシナリオをサポートするため、DorisはUnique Key Model、Aggregate Key Model、Duplicate Key Modelの3つのTableモデルを提供しています。これらの中で、Unique Key Modelは複雑で高頻度なデータ更新を実装するための中核です。

1.1. Tableモデル概要

Table Model主要機能更新機能使用ケース
Unique Key Modelリアルタイム更新のために構築されています。各データ行は一意のPrimary Keyによって識別され、行レベルのUPSERT(アップデート/Insert)と部分カラム更新をサポートします。最強、すべての更新・削除方法をサポートします。注文ステータス更新、リアルタイムユーザータグ計算、CDCデータ同期、その他の頻繁でリアルタイムな変更が必要なシナリオ。
Aggregate Key Model指定されたKeyカラムに基づいてデータを事前集約します。同一のKeyを持つ行については、Valueカラムが定義された集約関数(SUM、MAX、MIN、REPLACEなど)に従ってマージされます。限定的、KeyカラムベースのREPLACEスタイルの更新・削除をサポートします。リアルタイムサマリー統計が必要なシナリオ(リアルタイムレポート、広告クリック統計など)。
Duplicate Key Modelデータはappend-onlyの書き込みのみをサポートし、重複排除や集約操作は行いません。同一のデータ行も保持されます。限定的、DELETE文による条件削除のみをサポートします。ログ収集、ユーザー行動追跡、その他の更新なしで追加のみが必要なシナリオ。

1.2. データ更新方法

Dorisは2つの主要カテゴリのデータ更新方法を提供します:データロードによる更新DML文による更新です。

1.2.1. ロードによる更新(UPSERT)

これはDorisの推奨される高性能・高並行性の更新方法で、主にUnique Key Modelを対象としています。すべてのロード方法(Stream Load、Broker Load、Routine Load、INSERT INTO)は自然にUPSERTセマンティクスをサポートします。新しいデータがロードされる際、そのプライマリキーが既に存在する場合、Dorisは古い行データを新しい行データで上書きし、プライマリキーが存在しない場合は新しい行を挿入します。

img

1.2.2. UPDATE DML文による更新

Dorisは標準SQL UPDATE文をサポートし、ユーザーがWHERE句で指定された条件に基づいてデータを更新できます。この方法は非常に柔軟で、Table間結合更新などの複雑な更新ロジックをサポートします。

img

-- Simple update
UPDATE user_profiles SET age = age + 1 WHERE user_id = 1;

-- Cross-table join update
UPDATE sales_records t1
SET t1.user_name = t2.name
FROM user_profiles t2
WHERE t1.user_id = t2.user_id;

注意: UPDATE文の実行プロセスは、まず条件を満たすデータをスキャンし、その後更新されたデータをTableに書き戻すことを含みます。低頻度のバッチ更新タスクに適しています。UPDATE文での高並行操作は推奨されません。同一のプライマリキーを含む並行UPDATE操作では、データの分離を保証できないためです。

1.2.3. INSERT INTO SELECT DML文による更新

DorisはデフォルトでUPSERTセマンティクスを提供するため、INSERT INTO SELECTを使用することでUPDATEと同様の更新効果を実現することもできます。

1.3. データ削除方法

更新と同様に、DorisはロードとDML文の両方を通じてデータの削除もサポートしています。

1.3.1. ロードによるマーク削除

これは効率的なバッチ削除方法で、主にUnique Key Modelで使用されます。ユーザーはデータをロードする際に、特別な隠し列DORIS_DELETE_SIGNを追加できます。この列の値が行で1またはtrueの場合、Dorisはそのプライマリキーに対応するデータ行を削除済みとしてマークします(削除サインの原理については後で詳しく説明します)。

// Stream Load load data, delete row with user_id = 2
// curl --location-trusted -u user:passwd -H "columns:user_id, __DORIS_DELETE_SIGN__" -T delete.json http://fe_host:8030/api/db_name/table_name/_stream_load

// delete.json content
[
{"user_id": 2, "__DORIS_DELETE_SIGN__": "1"}
]

1.3.2. DELETE DML文による削除

DorisはWHERE条件に基づいてデータを削除できる標準SQL DELETE文をサポートしています。

  • Unique Key Model: DELETE文は条件に合致する行のプライマリキーを削除マークで書き換えます。そのため、そのパフォーマンスは削除対象データ量に比例します。Unique Key ModelにおけるDELETE文の実行原理はUPDATE文と非常に似ており、まずクエリを通じて削除対象データを読み取り、次に削除マークを付けて再度書き込みます。UPDATE文と比較して、DELETE文はKeyカラムと削除マークカラムのみを書き込めばよいため、比較的軽量です。
  • Duplicate/Aggregate Models: DELETE文はdelete predicateを記録することで実装されます。クエリ時には、このpredicateがランタイムフィルターとして機能し、削除されたデータをフィルタリングします。そのため、DELETE操作自体は非常に高速で、削除データ量にほぼ依存しません。ただし、Duplicate/Aggregate Modelに対する高頻度の DELETE 操作は多くのランタイムフィルターを蓄積し、その後のクエリパフォーマンスに深刻な影響を与えることに注意してください。
DELETE FROM user_profiles WHERE last_login < '2022-01-01';

以下の表では、削除におけるDML文の使用について簡潔にまとめています:

Unique Key ModelAggregate ModelDuplicate Model
ImplementationDelete SignDelete PredicateDelete Predicate
LimitationsNoneDelete conditions only for Key columnsNone
Deletion PerformanceModerateFastFast

2. Unique Key Modelの詳細解説:原理と実装

Unique Key ModelはDorisの高性能リアルタイム更新の要です。そのパフォーマンスを十分に活用するためには、内部動作原理を理解することが重要です。

2.1. Merge-on-Write (MoW) vs. Merge-on-Read (MoR)

Unique Key Modelには2つのデータマージ戦略があります:Merge-on-Write (MoW)とMerge-on-Read (MoR)です。Doris 2.1以降、MoWがデフォルトかつ推奨の実装となっています

機能Merge-on-Write (MoW)Merge-on-Read (MoR) - (Legacy)
基本概念データ書き込み時にデータ重複排除とマージを完了し、ストレージ内で主キーごとに最新レコードのみが存在することを保証します。データ書き込み時に複数のバージョンを保持し、クエリ時にリアルタイムマージを実行して最新バージョンを返します。
クエリパフォーマンス極めて高性能です。クエリ時に追加のマージ操作が不要で、パフォーマンスは非更新詳細Tableに近づきます。低性能です。クエリ時にデータマージが必要で、MoWより約3-10倍時間がかかり、CPUとメモリをより多く消費します。
書き込みパフォーマンス書き込み時にマージのオーバーヘッドがあり、MoRと比較してパフォーマンスが低下します(小バッチで約10-20%、大バッチで30-50%)。書き込み速度が速く、詳細Tableに近い性能です。
リソース消費書き込みとバックグラウンドCompaction時により多くのCPUとメモリを消費します。クエリ時により多くのCPUとメモリを消費します。
使用ケース大部分のリアルタイム更新シナリオ。特に読み取り集約型、書き込み軽量型のビジネスに適しており、究極のクエリ分析パフォーマンスを提供します。書き込み集約型、読み取り軽量型のシナリオに適していますが、もはや主流の推奨ではありません。

MoWメカニズムは書き込み段階での小さなコストと引き換えに、クエリパフォーマンスの大幅な改善を実現し、OLAPシステムの「読み取り集約型、書き込み軽量型」の特性に完全に適合します。

2.2. 条件付き更新(Sequence Column)

分散システムでは、データの順序外到着は一般的な問題です。例えば、注文ステータスが順次「支払済み」と「出荷済み」に変わるものの、ネットワーク遅延により「出荷済み」を表すデータが「支払済み」を表すデータよりも先にDorisに到着する可能性があります。

この問題を解決するため、DorisはSequence Columnメカニズムを導入しています。ユーザーはTable作成時に列(通常はタイムスタンプやバージョン番号)をSequence columnとして指定できます。同じ主キーのデータを処理する際、DorisはそれらのSequence column値を比較し、常に最大のSequence値を持つ行を保持し、データが順序外で到着しても最終的な一貫性を確保します。

CREATE TABLE order_status (
order_id BIGINT,
status_name STRING,
update_time DATETIME
)
UNIQUE KEY(order_id)
DISTRIBUTED BY HASH(order_id)
PROPERTIES (
"function_column.sequence_col" = "update_time" -- Specify update_time as Sequence column
);

-- 1. Write "Shipped" record (larger update_time)
-- {"order_id": 1001, "status_name": "Shipped", "update_time": "2023-10-26 12:00:00"}

-- 2. Write "Paid" record (smaller update_time, arrives later)
-- {"order_id": 1001, "status_name": "Paid", "update_time": "2023-10-26 11:00:00"}

-- Final query result, retains record with largest update_time
-- order_id: 1001, status_name: "Shipped", update_time: "2023-10-26 12:00:00"

2.3. 削除メカニズム(DORIS_DELETE_SIGN)のワークフロー

DORIS_DELETE_SIGNの動作原理は「論理的マーキング、バックグラウンドクリーンアップ」として要約できます。

  1. 削除の実行: ユーザーがloadまたはDELETE文を通じてデータを削除する際、Dorisは物理ファイルからデータを即座に削除しません。代わりに、削除される主キーに対して新しいレコードを書き込み、DORIS_DELETE_SIGN列を1としてマークします。
  2. クエリフィルタリング: ユーザーがデータをクエリする際、DorisはクエリプランにWHERE DORIS_DELETE_SIGN = 0というフィルター条件を自動的に追加し、削除マークされたすべてのデータをクエリ結果から隠します。
  3. バックグラウンドCompaction: DorisのバックグラウンドCompactionプロセスは定期的にデータをスキャンします。通常のレコードと削除マークレコードの両方を持つ主キーを発見すると、マージプロセス中に両方のレコードを物理的に削除し、最終的にストレージ領域を解放します。

このメカニズムにより、削除操作への迅速な応答を確保しつつ、バックグラウンドタスクを通じて物理的なクリーンアップを非同期的に完了し、オンラインビジネスへのパフォーマンス影響を回避します。

以下の図はDORIS_DELETE_SIGNの動作を示しています:

img

2.4 部分列更新

バージョン2.0から、DorisはUnique Key Models(MoW)で強力な部分列更新機能をサポートしています。データロード時、ユーザーは主キーと更新する列のみを提供すれば十分で、提供されない列は元の値を変更せずに維持されます。これにより、ワイドTable結合やリアルタイムタグ更新などのシナリオにおけるETLプロセスが大幅に簡素化されます。

この機能を有効にするには、Unique Key ModelTableを作成する際にMerge-on-Write(MoW)モードを有効にし、enable_unique_key_partial_updateプロパティをtrueに設定するか、データロード時に"partial_columns"パラメータを設定する必要があります。

CREATE TABLE user_profiles (
user_id BIGINT,
name STRING,
age INT,
last_login DATETIME
)
UNIQUE KEY(user_id)
DISTRIBUTED BY HASH(user_id)
PROPERTIES (
"enable_unique_key_partial_update" = "true"
);

-- Initial data
-- user_id: 1, name: 'Alice', age: 30, last_login: '2023-10-01 10:00:00'

-- load partial update data through Stream Load, only updating age and last_login
-- {"user_id": 1, "age": 31, "last_login": "2023-10-26 18:00:00"}

-- Updated data
-- user_id: 1, name: 'Alice', age: 31, last_login: '2023-10-26 18:00:00'

部分カラム更新の原理概要

従来のOLTPデータベースとは異なり、Dorisの部分カラム更新は、インプレースでのデータ更新ではありません。Dorisでより良い書き込みスループットとクエリパフォーマンスを実現するため、Unique Key Modelsの部分カラム更新は**「ロード時の欠損フィールド補完、その後の全行書き込み」**という実装アプローチを採用しています。

したがって、Dorisの部分カラム更新を使用すると**「リード増幅」「ライト増幅」**の効果があります。例えば、100カラムの幅の広いTableで10フィールドを更新する場合、Dorisは書き込みプロセス中に欠損している90フィールドを補完する必要があります。各フィールドが同様のサイズであると仮定すると、1MBの10フィールド更新では、Dorisシステムで約9MBのデータ読み取り(欠損フィールドの補完)と10MBのデータ書き込み(完全な行を新しいファイルに書き込み)が発生し、約9倍のリード増幅と10倍のライト増幅が生じます。

部分カラム更新のパフォーマンス推奨事項

部分カラム更新におけるリードおよびライト増幅により、Dorisは列指向ストレージシステムであるため、データ読み取りプロセスで大量のランダムI/Oが発生し、ストレージには高いランダムリードIOPSが要求されます。従来の機械式ディスクはランダムI/Oに大きなボトルネックがあるため、高頻度の書き込みに部分カラム更新機能を使用したい場合は、SSDドライブ、できればNVMe interfaceを推奨します。これにより最適なランダムI/Oサポートを提供できます。

さらに、Tableが非常に幅広い場合は、ランダムI/Oを削減するために行ストレージの有効化も推奨されます。行ストレージを有効にすると、Dorisは列指向ストレージと併せて行ベースデータの追加コピーを保存します。行ベースデータは各行を連続的に保存するため、単一のI/O操作で全行を読み取ることができます(列指向ストレージではすべての欠損フィールドを読み取るためにN回のI/O操作が必要です。例えば前述の100カラムの幅広いTableで10カラムを更新する場合、1行あたりすべてのフィールドを読み取るために90回のI/O操作が必要)。

3. 典型的なアプリケーションシナリオ

Dorisの強力なデータ更新機能により、様々な要求の厳しいリアルタイム分析シナリオを処理できます。

3.1. CDCリアルタイムデータ同期

Flink CDCなどのツールを通じて上流のビジネスデータベース(MySQL、PostgreSQL、Oracleなど)から変更データ(Binlog)をキャプチャし、Doris Unique Key ModelTableにリアルタイムで書き込むことは、リアルタイムデータウェアハウス構築の最も典型的なシナリオです。

  • データベース全体同期: Flink Doris Connectorは内部でFlink CDCを統合し、手動でのTable作成やフィールドマッピング設定なしに、上流データベースからDorisへの自動化されたエンドツーエンドのデータベース全体同期を実現します。
  • 整合性の確保: Unique Key ModelのUPSERT機能を利用して上流のINSERTおよびUPDATE操作を処理し、DORIS_DELETE_SIGNを使用してDELETE操作を処理し、Sequenceカラム(Binlogのタイムスタンプなど)と組み合わせて順序の乱れたデータを処理し、上流データベースの状態を完全に複製してミリ秒レベルのデータ同期遅延を実現します。

img

3.2. リアルタイム幅広Table結合

多くの分析シナリオでは、異なるビジネスシステムからのデータをユーザー幅広Tableや製品幅広Tableに結合する必要があります。従来のアプローチでは、定期的(T+1)結合にオフラインETLタスク(SparkやHiveなど)を使用しますが、これはリアルタイム性能が低く、メンテナンスコストが高くなります。または、Flinkを使用してリアルタイム幅広Table結合計算を行い、結合されたデータをデータベースに書き込む方法では、通常大量の計算リソースが必要です。

Dorisの部分カラム更新機能を使用することで、このプロセスを大幅に簡素化できます:

  1. DorisでUnique Key Model幅広Tableを作成します。
  2. Stream LoadやRoutine Loadを通じて、異なるソース(ユーザー基本情報、ユーザー行動データ、取引データなど)からのデータストリームをこの幅広Tableにリアルタイムで書き込みます。 3.各データストリームは関連するフィールドのみを更新します。例えば、ユーザー行動データストリームはpage_view_countlast_login_timeなどのフィールドのみを更新し、取引データストリームはtotal_orderstotal_amountなどのフィールドのみを更新します。

このアプローチは、幅広Table構築をオフラインETLからリアルタイムストリーム処理に変換してデータの新鮮さを大幅に向上させるだけでなく、変更されたカラムのみを書き込むことでI/Oオーバーヘッドを削減し、書き込みパフォーマンスを向上させます。

4. ベストプラクティス

これらのベストプラクティスに従うことで、Dorisのデータ更新機能をより安定して効率的に使用できます。

4.1. 一般的なパフォーマンスプラクティス

  1. load Updatesを優先する: 高頻度で大量の更新操作については、UPDATE DMLステートメントよりもStream LoadやRoutine Loadなどのloadメソッドを優先します。
  2. バッチ書き込み: 個別の高頻度書き込み(100 TPS超など)にINSERT INTOステートメントの使用を避けます。各INSERTにはトランザクションオーバーヘッドが発生するためです。必要な場合は、複数の小さなバッチコミットを1つの大きなトランザクションにマージするGroup Commit機能の有効化を検討してください。
  3. 高頻度DELETEの慎重な使用: Duplicate ModelやAggregate Modelでは、クエリパフォーマンスの低下を防ぐため、高頻度のDELETE操作を避けます。
  4. パーティションデータ削除にはTRUNCATE PARTITIONを使用: パーティション全体のデータを削除する必要がある場合は、DELETEよりもはるかに効率的なTRUNCATE PARTITIONを使用します。
  5. UPDATEの直列実行: 同じデータ行に影響する可能性のあるUPDATEタスクの並行実行を避けます。

4.2. コンピューティング・ストレージ分離アーキテクチャにおけるUnique Key Modelプラクティス

Doris 3.0は高度なコンピューティング・ストレージ分離アーキテクチャを導入し、究極の弾力性とより低いコストをもたらします。このアーキテクチャでは、BEノードがステートレスであるため、Merge-on-Writeプロセス中にMetaServiceを通じてグローバル状態を維持し、load/compaction/schema change操作間の書き込み-書き込み競合を解決する必要があります。Unique Key ModelのMoW実装は、書き込み操作の整合性を確保するためにMeta Serviceベースの分散Tableロックに依存しており、次の図に示されています:

img

高頻度のloadとCompactionはTableロックの頻繁な競合を引き起こすため、以下の点に特に注意を払う必要があります:

  1. 単一Tableのload頻度制御: 単一のUnique KeyTableのload頻度を60回/秒以内に制御することを推奨します。これは、バッチ処理とload並行性の調整により実現できます。
  2. 適切なパーティションとバケット設計:
    1. パーティション: 時間パーティション(日単位や時間単位など)を使用することで、単一のloadが少数のパーティションのみを更新することを確保し、ロック競合の範囲を削減します。
    2. バケット: バケット数(Tablet数)は、データ量に基づいて適切に設定し、通常8-64の間にします。Tabletが多すぎるとロック競合が激化します。
  3. Compaction戦略の調整: 非常に高い書き込み圧力のシナリオでは、Compaction頻度を削減してCompactionとloadタスク間のロック競合を削減するため、Compaction戦略を適切に調整できます。
  4. 最新バージョンへのアップグレード: Dorisコミュニティは、コンピューティング・ストレージ分離アーキテクチャでのUnique Key Modelパフォーマンスを継続的に最適化しています。例えば、近日リリース予定の3.1では分散Tableロック実装を大幅に最適化しています。最適なパフォーマンスのため、常に最新安定版の使用を推奨します

まとめ

Apache Dorisは、Unique Key Modelを中心とした強力で柔軟かつ効率的なデータ更新機能により、従来のOLAPシステムにおけるデータの新鮮さのボトルネックを真に突破しています。UPSERTと部分カラム更新を実装する高性能なloadや、順序の乱れたデータの整合性を確保するSequenceカラムの使用など、Dorisはエンドツーエンドのリアルタイム分析アプリケーション構築のための完全なソリューションを提供します。

その中核原理を深く理解し、異なる更新メソッドの適用シナリオを習得し、この文書で提供されているベストプラクティスに従うことで、Dorisの潜在能力を完全に引き出し、リアルタイムデータを真にビジネス成長を推進する強力なエンジンにすることができるでしょう。