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

データ更新概要

今日のデータ主導意思決定の状況において、データの「新鮮さ」は、企業が激しい市場競争で際立つための中核的な競争優位性となっています。従来のT+1データ処理モデルは、その固有のレイテンシーのため、現代のビジネスの厳しいリアルタイム要件をもはや満たすことができません。ビジネスデータベースとデータウェアハウス間でのミリ秒レベルの同期の実現、運用戦略の動的調整、または意思決定の精度を確保するための数秒以内での誤ったデータの修正など、堅牢なリアルタイムデータ更新機能が不可欠です。

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

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

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

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

1.1. テーブルモデル概要

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

1.2. データ更新方法

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

1.2.1. Load による更新(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句で指定された条件に基づいてデータを更新できます。この方法は非常に柔軟で、テーブル間結合更新などの複雑な更新ロジックをサポートしています。

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文の実行プロセスは、まず条件を満たすデータをスキャンし、その後更新されたデータをテーブルに書き戻すことを含みます。これは低頻度のバッチ更新タスクに適しています。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はその主キーを持つ対応するデータ行を削除済みとしてマークします(delete signの原理については後で詳しく説明します)。

// 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は標準SQL DELETE文をサポートしており、WHERE条件に基づいてデータを削除できます。

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

以下の表は、削除にDMLステートメントを使用することの簡単な要約を示しています:

Unique Key ModelAggregate ModelDuplicate Model
実装方式Delete SignDelete PredicateDelete Predicate
制限事項なしKey列に対する削除条件のみなし
削除パフォーマンス中程度高速高速

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) - (レガシー)
コアコンセプトデータ書き込み時にデータの重複排除とマージを完了し、ストレージ内で主キーごとに最新のレコードが1つだけ存在することを保証します。データ書き込み時に複数のバージョンを保持し、クエリ時にリアルタイムでマージを実行して最新バージョンを返します。
クエリパフォーマンス非常に高い。クエリ時に追加のマージ操作が不要で、パフォーマンスは更新されていない詳細テーブルに近くなります。低い。クエリ時にデータマージが必要で、MoWより約3-10倍時間がかかり、CPUとメモリをより多く消費します。
書き込みパフォーマンス書き込み時にマージのオーバーヘッドがあり、MoRと比較してパフォーマンスが低下します(小さなバッチで約10-20%、大きなバッチで30-50%)。書き込み速度が速く、詳細テーブルに近いパフォーマンスです。
リソース消費量書き込み時とバックグラウンドのCompaction時により多くのCPUとメモリを消費します。クエリ時により多くのCPUとメモリを消費します。
ユースケースほとんどのリアルタイム更新シナリオ。特に読み取り重視、書き込み軽量のビジネスに適しており、究極のクエリ分析パフォーマンスを提供します。書き込み重視、読み取り軽量のシナリオに適していますが、もはや主流の推奨ではありません。

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

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

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

この問題を解決するため、DorisはSequence Columnメカニズムを導入しています。ユーザーはテーブル作成時に列(通常はタイムスタンプやバージョン番号)をSequence列として指定できます。同じ主キーを持つデータを処理する際、DorisはそれらのSequence列の値を比較し、常に最大の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)において強力な部分列更新機能をサポートしています。データロード時、ユーザーは主キーと更新対象列のみを提供すればよく、提供されていない列は元の値を変更せずに維持します。これにより、ワイドテーブル結合やリアルタイムタグ更新などのシナリオでのETLプロセスが大幅に簡素化されます。

この機能を有効にするには、Unique Key Modelテーブル作成時に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列の幅広いテーブルで10個のフィールドを更新する場合、Dorisは書き込みプロセス中に欠損している90個のフィールドを補完する必要があります。各フィールドが同様のサイズであると仮定すると、1MBの10フィールド更新では、Dorisシステム内で約9MBのデータ読み込み(欠損フィールドの補完)と10MBのデータ書き込み(完全な行を新しいファイルに書き込み)が生成され、約9倍の読み込み増幅と10倍の書き込み増幅が発生します。

部分列更新パフォーマンス推奨事項

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

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

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

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

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

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

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

img

3.2. リアルタイム幅広いテーブルのジョイン

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

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

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

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

4. ベストプラクティス

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

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

  1. load更新を優先: 高頻度で大量の更新操作では、UPDATE DMLステートメントよりもStream LoadやRoutine Loadなどのloadメソッドを優先します。
  2. バッチ書き込み: 個別の高頻度書き込み(> 100 TPSなど)でのINSERT INTOステートメントの使用を避けます。各INSERTには取引オーバーヘッドが発生するためです。必要な場合は、Group Commit機能の有効化を検討し、複数の小さなバッチコミットを1つの大きな取引にマージします。
  3. 高頻度DELETEの慎重な使用: DuplicateおよびAggregateモデルでは、クエリパフォーマンスの低下を防ぐため、高頻度の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ベースの分散テーブルロックに依存して書き込み操作の一貫性を確保します。以下の図に示されています:

img

高頻度のloadとCompactionはテーブルロックの頻繁な競合につながるため、以下の点に特別な注意を払う必要があります:

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

結論

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

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