---
title: "ClickHouseのUPDATEを1,000倍高速化した方法 (パート3: ベンチマーク)"
date: "2026-09-25T07:21:26.514Z"
author: "Tom Schreiber"
category: "Engineering"
excerpt: "ClickHouseは軽量なパッチパート更新による標準SQLのUPDATEに対応しました。テストでは従来のミューテーションと比べて最大1,000倍高速化し、最悪のケースでもクエリのオーバーヘッドはごくわずかです。"
---

# ClickHouseのUPDATEを1,000倍高速化した方法 (パート3: ベンチマーク)

<style>
/* Expandable metric boxes */
details.metric-box {
  background: #2B2B2B;
  border-radius: 12px;
  margin: 28px 0;
  padding: 0;
  color: #E2E8F0;
  box-shadow: 0 0 0 1px rgba(255,255,255,0.05), 0 4px 12px rgba(0,0,0,0.2);
  border-left: 5px solid rgba(255, 255, 255, 0.1);
}

/* Summary bar */
details.metric-box summary {
  cursor: pointer;
  list-style: none;
  padding: 16px 24px;
  font-weight: 600;
  font-size: 14px;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: #E2E8F0;
  position: relative;
  transition: background 0.2s;
}

details.metric-box summary:hover {
  background: rgba(255,255,255,0.05);
}

/* Rotating arrow */
details.metric-box summary::after {
  content: "▶";
  position: absolute;
  right: 20px;
  transition: transform 0.2s;
  font-size: 12px;
  color: #A0AEC0;
}

details.metric-box[open] summary::after {
  transform: rotate(90deg);
}

/* Inner content */
details.metric-box p {
  padding: 0 24px 12px 24px;
  margin: 0;
  font-size: 15px;
  line-height: 1.55;
}

details.metric-box .notes {
  margin: 12px 24px 16px 24px;
  padding: 10px 12px;
  background: rgba(255,255,255,0.05);
  border-radius: 6px;
  font-size: 14px;
}

details.metric-box a { color: inherit; text-decoration: none; }
details.metric-box code {
  background: rgba(255,255,255,0.06);
  padding: 2px 5px;
  border-radius: 4px;
  font-family: ui-monospace, SFMono-Regular, monospace;
}

/* Metrics table inside expandable boxes */
details.metric-box.metrics .metric-row {
  display: flex;
  padding: 6px 0;
  border-bottom: 1px solid rgba(255,255,255,0.05);
  font-size: 14px;
  margin: 0 24px;
}
details.metric-box.metrics .metric-row:last-child { border-bottom: none; }

details.metric-box.metrics .metric-label {
  width: 180px;
  text-align: right;
  padding-right: 16px;
  color: #A0AEC0;
  flex-shrink: 0;
}
details.metric-box.metrics .metric-value { flex: 1; }
</style>

> **TL;DR**<br/><br/>
標準 SQL の UPDATE が ClickHouse に登場しました。軽量なパッチパート更新により、ミューテーションと比べて最大 **1,000 倍高速** です。

<div style="margin-bottom: 0.5em;">
  <strong>本記事は、ClickHouse における高速な UPDATE に関する連載記事の一部です:</strong>
</div>
<ul style="margin-top: 0.2em;">
  <li>
    <strong><a href="https://clickhouse.com/ja/blog/updates-in-clickhouse-1-purpose-built-engines-jp">第 1 回: 専用エンジンの活用</a></strong><br/>
    ReplacingMergeTree、CollapsingMergeTree、CoalescingMergeTree などの挿入ベースのエンジンを使用し、ClickHouse が低速な行レベル更新をどのように回避しているかを解説します。
  </li>
  <li>
    <strong><a href="https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp">第 2 回: 宣言型 SQL スタイルの UPDATE</a></strong><br/>
    パッチパートを用いて最小限のオーバーヘッドで標準の UPDATE 構文を ClickHouse に導入した仕組みを探ります。
  </li>
  <li>
    <strong>本記事: ベンチマークと結果</a></strong><br/>
    実際の処理速度を確認します。宣言型 UPDATE を含む各手法のベンチマークを実施し、最大 <strong>1,000 倍の高速化</strong> を確認しました。
  </li>
    <li>
    <strong><a href="https://clickhouse.com/ja/blog/update-performance-clickhouse-vs-postgresql-jp">番外編: ClickHouse と PostgreSQL の比較</a></strong><br/>
    同一のハードウェアとデータで、ClickHouse の新しい SQL UPDATE を PostgreSQL と直接対決させました。単一行の更新では同等、一括変更では最大 <strong>4,000 倍高速</strong> という結果が得られました。
  </li>
</ul>



## ClickHouse における高速な SQL UPDATE: ベンチマークとエスプレッソを飲んだリス

リスを思い浮かべてみてください。小さく、すばしっこく、隠し場所の間を駆け回り、新しい木の実を素早く落とし込んでいきます。

では、そのリスが**エスプレッソを飲んだ**ところを想像してください。*信じられないほどの猛スピード*で、まばたきする間もなく隠し場所の間を疾走します。

**ClickHouse の軽量な更新 (Lightweight update)** は、まさにその感覚です。データパート間を素早く駆け回り、瞬時に適用される極小のパッチを配置して、**クエリの高速性を維持**します。

> **要点**: これらは軽量パッチパート機構で実装された完全な標準 SQL UPDATE です。今回のベンチマークでは、標準 SQL の一括 UPDATE が **100 秒ではなく 60 ms で完了し、従来のミューテーション比で 1,600 倍高速** でした。また、最悪のシナリオでのクエリ実行でも、完全に書き換えられたデータとほぼ同等の速度で動作します。

本記事は ClickHouse での高速な UPDATE に関する深掘り連載の**第 3 回**であり、**全編ベンチマーク特集**となっています。<br/>(この高速化を*どのように*実現したかを知りたい場合は、**[第 2 回: SQL スタイルの UPDATE](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)** をご覧ください。)

ここでは、**すべての UPDATE 手法を並べてベンチマーク**します:



* **従来のミューテーションとオンザフライミューテーション**
* **軽量な更新 (パッチパート)**
* **ReplacingMergeTree による挿入**

検証の焦点は以下の 2 点です:

1. **更新速度と可視性** – 各手法で変更がどれだけ早く反映されるか

2. **マージ前のクエリへの影響** – 実体化される前の更新がレイテンシにどう影響するか

オープンソースとして公開しているスクリプトとクエリにより、すべて**完全に再現可能**です。

まずは**データセットとベンチマーク環境の概要**を説明し、その後に測定結果を見ていきます。


## データセットとベンチマーク環境


### データセット

[第 1 回](https://clickhouse.com/ja/blog/updates-in-clickhouse-1-purpose-built-engines-jp)と[第 2 回](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)では、基本的な更新シナリオを説明するために小さな注文 (orders) テーブルを使用しました。

今回のベンチマークでも同じ「注文」のテーマを引き継ぎますが、顧客注文の明細をモデル化した **[TPC-H](https://clickhouse.com/docs/ja/get-started/sample-datasets/tpch) の lineitem テーブル** を使ってスケールアップしています。これは、初回挿入後に数量、価格、割引率などが変更されるという、更新の代表的なシナリオです:
<pre>
<code type='click-ui' language='sql' show_line_numbers='false'>
CREATE TABLE lineitem (
    l_orderkey       Int32,
    l_partkey        Int32,
    l_suppkey        Int32,
    l_linenumber     Int32,
    l_quantity       Decimal(15,2),
    l_extendedprice  Decimal(15,2),
    l_discount       Decimal(15,2),
    l_tax            Decimal(15,2),
    l_returnflag     String,
    l_linestatus     String,
    l_shipdate       Date,
    l_commitdate     Date,
    l_receiptdate    Date,
    l_shipinstruct   String,
    l_shipmode       String,
    l_comment        String)
ORDER BY (l_orderkey, l_linenumber);
</code>
</pre>

このテーブルの**スケールファクター 100** バージョンを使用します。これには約 **6 億行** (~1 億 5,000 万件の注文からなる約 6 億件の明細) が含まれ、**圧縮後で約 30 GiB** (非圧縮で約 60 GiB) を占めます。

ベンチマークでは、lineitem テーブルを単一の[データパート](https://clickhouse.com/docs/ja/concepts/core-concepts/parts)として保存しています。圧縮後のサイズである約 30 GiB は、バックグラウンドマージによって小さなパートが 1 つにまとめられる ClickHouse の圧縮マージ[しきい値](https://clickhouse.com/docs/ja/reference/settings/merge-tree-settings) (150 GiB) を十分に下回っています。これにより、テーブルは自然に単一の完全にマージされたパートとして存在し、現実的な更新シナリオを再現できます。

以下は、すべてのベンチマーク実行で使用した lineitem [ベーステーブル](https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/init.sh#L68)の概要であり、単一パートのサイズを確認できます:
<pre>
<code type='click-ui' language='sql' show_line_numbers='false'>
SELECT
    formatReadableQuantity(sum(rows)) AS row_count,
    formatReadableQuantity(count()) AS part_count,
    formatReadableSize(sum(data_uncompressed_bytes)) AS size_uncomp,
    formatReadableSize(sum(data_compressed_bytes)) AS size_comp
FROM system.parts
WHERE active AND database = 'default' AND `table` = 'lineitem_base_tbl_1part';
</code>
</pre>

<pre><code type='click-ui' language='text' show_line_numbers='false'>
┌─row_count──────┬─part_count─┬─size_uncomp─┬─size_comp─┐
│ 600.04 million │ 1.00       │ 57.85 GiB   │ 26.69 GiB │
└────────────────┴────────────┴─────────────┴───────────┘
</code></pre>

### ハードウェアと OS

**Ubuntu 24.04 LTS** を実行する **AWS m6i.8xlarge** EC2 インスタンス (32 コア、128 GB RAM) と **gp3 EBS ボリューム** (16,000 IOPS、最大スループット 1,000 MiB/s) を使用しました。


### ClickHouse バージョン

すべてのテストは **ClickHouse 25.7** で実施しました。


### 自身での検証の実行

[GitHub 上のベンチマークスクリプト](https://github.com/ClickHouse/examples/tree/main/blog-examples/clickhouse-fast-updates) を使用して、すべての結果を再現できます。

リポジトリには以下が含まれています:

* 更新ステートメントセット (一括更新および単一行更新)
* ベンチマークを実行して所要時間を収集するスクリプト
* データパートのサイズとクエリへの影響を調査するためのヘルパー

環境とデータセットが整ったので、多くのパイプラインの根幹である一括更新から順に、各種更新手法の挙動を見ていきましょう。


## 一括 UPDATE

まずは、バッチパイプラインの根幹であり従来のミューテーションで最も一般的なワークロードである一括更新から始めます。

GitHub 上の SQL スクリプトにリンクされた 3 つの手法を用いて、**10 種類の典型的な一括更新** をベンチマークしました:

1. **[ミューテーション](https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/SMALL/mutation_updates.sql)** – 影響を受けるデータパートの**完全な書き換え**をトリガーします。

2. **[軽量な更新](https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/SMALL/lightweight_updates.sql)** – **小さなパッチパート**のみをディスクに書き込みます。<br/>([標準の SQL UPDATE ステートメント](https://www.w3schools.com/sql/sql_update.asp)を使用します。「軽量」という名称は効率的なパッチパート実装のみを指します。)

3. **[オンザフライミューテーション](https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/SMALL/mutation_updates.sql)** – **ミューテーションと同じ構文**を使用しますが、**更新式をメモリ内にのみ保持**し、読み取り時に適用します。完全なカラムの書き換えは非同期に行われます。

**注意:**

* ここでは宣言型の更新に焦点を当てています。**ReplacingMergeTree** のような専用エンジンは、1 行ずつの挿入による一括更新が実用的ではないため、複数行のベンチマークからは除外しています。(後ほど、これらのエンジン向けに**単一行更新**を取り上げます。)

* `DELETE` については個別にベンチマークを行っていません。`DELETE` は `_row_exists` を[書き換える](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)従来のミューテーションか、そのマスクの[軽量パッチ](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)のいずれかであり、両方のメカニズムは上記ですでに検証されています。

(ここからグラフが続きます。結果だけを確認したい場合は、各セクションの「測定方法」ボックスをスキップしてください。)
<details class="metric-box">
  <summary>測定方法 – 一括更新の実行時間 (クリックして展開)</summary>
  <p><span class="step-num">1.</span> <code>lineitem</code> テーブルが存在する場合は <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/run_updates_sequential.sh#L84" target="_blank">DROP</a> します。</p>
  <p><span class="step-num">2.</span> ベーステーブルから新しい <code>lineitem</code> テーブルを <a href="https://clickhouse.com/blog/clickhouse-release-24-10#table-cloning" target="_blank">クローン</a> します。</p>
  <p><span class="step-num">3.</span> <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/run_updates_sequential.sh#L96" target="_blank">更新を実行して実行時間を測定</a> します。</p>
  <p>手法ごとに <b>3 回繰り返し</b>、平均実行時間を算出します。<br>この手順を <b>10 個の一括更新すべて</b> について繰り返します。</p>
</details>

###  一括更新がクエリから参照可能になるまでの時間

10 個の一括 UPDATE それぞれについて、下のグラフは **UPDATE を発行してからその変更がクエリから参照可能になるまでの時間** を測定し、3 つの手法すべてを比較しています。

また、クエリが変更を確認できるようになる前に影響を受けるデータパートの書き換えを完了しなければならない従来のミューテーションに対して、**軽量な更新がどれだけ高速か (% 表示)** も示しています。

<details class="metric-box metrics">
  <summary>グラフ内のその他の主要指標 (クリックして展開)</summary>
  <div class="metric-row"><div class="metric-label">Rows upd / Cols upd</div><div class="metric-value">UPDATE の対象となった行数とカラム数</div></div>
  <div class="metric-row"><div class="metric-label">Full cols size</div><div class="metric-value">従来のミューテーションが書き換えるバイト数</div></div>
  <div class="metric-row"><div class="metric-label">Upd data size</div><div class="metric-value">軽量な更新によって実際に書き込まれたバイト数</div></div>
</details>

![Blog-updates Part 3.001.png](https://cms.clickhouse-dev.com:1337/uploads/Blog_updates_Part_3_001_9bb4cf35e5.png)

* **オンザフライミューテーション —** クエリされたデータに*即座に*適用できるように、[更新式がメモリに保持](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)されます。

* **従来のミューテーション —** 最も低速なパスです。クエリが新しいデータを参照できるようになる**前**に、すべての変更がディスク上の[カラム全体を書き換え](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)ます。

* **軽量な更新 —** クエリ実行時に瞬時に組み込まれる[小さな「パッチパート」を書き込む](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)ことで、最大 **1,700 倍高速** です。


*これらのグラフの元となった JSON ファイルについては、[生のベンチマーク結果](https://github.com/ClickHouse/examples/tree/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/results) を参照してください。*

*各手法の間で処理速度に違いが生じる**理由**は、後の詳細解説で詳しく説明します。*

高速な更新は素晴らしいものですが、それがクエリを損なわないことが前提です。各手法がクエリパフォーマンスにどのような影響を与えるかを見ていきましょう。


### 更新後の最悪条件下でのクエリ時間 — 一括更新

> **完全に実体化された後は、使用した更新手法に関係なくクエリパフォーマンスは同一になります**。

バックグラウンド処理が完了すると、テーブルのデータパートは完全に更新され、クエリは UPDATE 手法に関係なくベースラインの速度で動作します:



* **ミューテーション** – データパートは即座に[書き換えられ](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)ます。

* **オンザフライミューテーション** – バックグラウンドでのカラム書き換えによって、メモリ内の更新式が[最終的に実体化](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)されます。

* **軽量な更新** – パッチパートは通常のバックグラウンドマージによってメインのデータパートに[マージ](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)されます。


そのため、パフォーマンスを最も控えめに見積もる指標として**更新後の最悪条件下でのクエリ時間**を測定します。これは、*ディスク上で変更が完全に実体化される前に、更新されたばかりの行にヒットするクエリの実行時間*として定義されます。

次に、従来のミューテーションがすべての更新をディスクに書き終えた後に同じデータにヒットするクエリのベースライン時間と比較して、これがどれだけ遅いか (速度低下率のパーセンテージ) を示します。


<details class="metric-box">
  <summary>測定方法 – 一括更新後の最悪条件下でのクエリ時間 (クリックして展開)</summary>
  <p>• 10 個の更新と 1 対 1 で対になる <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/SMALL/analytical_queries.sql" target="_blank">10 個の分析クエリ</a> を使用します。</p>
  <p>• 各更新後に対になるクエリを 3 回 <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/run_updates_sequential.sh#L141" target="_blank">実行</a> し、<b>平均実行時間とメモリ使用量</b> を測定します。</p>
  <div class="notes">
    <b>注意:</b><br>
    • <b>各クエリは少なくとも更新された行とカラムを読み取ります</b>が、現実的な分析を想定してより広範なデータをスキャンするものも多くあります。<br>
    • <b>最悪条件のレイテンシ</b>を捉えるため、ベンチマークでは <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/run_updates_sequential.sh#L92" target="_blank">バックグラウンドマージを無効化</a> しています:<br>
    <div style="margin-left:20px;margin-top:4px;">
      • <b>オンザフライミューテーション</b> は純粋にメモリ内にとどまります。<br>
      • <b>軽量な更新</b> は Patch-on-read (暗黙的な FINAL) に依存します。
    </div>
  </div>
</details>


次のグラフは、完全に実体化された更新のベースラインと比較した、各タイプの一括 UPDATE 後における [10 個のクエリ](https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/SMALL/analytical_queries.sql) 全部の**更新後の最悪条件下でのクエリ時間**を示しています:

<details class="metric-box metrics">
  <summary>グラフ内のその他の主要指標 (クリックして展開)</summary>
  <div class="metric-row"><div class="metric-label">Slowdown %</div><div class="metric-value">完全に実体化された (ミューテーション) ベースラインに対する追加の実行時間</div></div>
  <div class="metric-row"><div class="metric-label">Memory (MiB)</div><div class="metric-value">クエリによって使用されたピークメモリ</div></div>
  <div class="metric-row"><div class="metric-label">Memory Δ (%)</div><div class="metric-value">ベースラインに対するメモリ使用量の変化率</div></div>
</details>

![Blog-updates Part 3.002.png](https://cms.clickhouse-dev.com:1337/uploads/Blog_updates_Part_3_002_dd391239df.png)

* **従来のミューテーション (ベースライン)** → 同期ミューテーションがディスク上の影響を受けるデータパートを完全に書き換えた後のクエリ実行時間。

* **軽量な更新** → デフォルトでオーバーヘッドは最小限 (平均 15%)、[ファストマージモード](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp) ではわずか 8〜21% の速度低下にとどまります。

* **軽量な更新のまれなフォールバック** → パッチ作成と並行してソースパートがマージされた場合、[低速な JOIN モード](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp) が発生することがあります (39〜121% のオーバーヘッド)。

* **オンザフライミューテーション** → 即座に可視化されますが、**最大の速度低下** を引き起こします (12〜427%、平均 149%)。


**メモリへの影響** → オンザフライは ~0.7 MiB から ~302 MiB へ急増することがありますが、軽量な更新は非常に控えめな状態を維持します。

*[生のベンチマーク結果はこちら →](https://github.com/ClickHouse/examples/tree/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/results)*

*これらの速度低下とメモリ変化の背景にある仕組みについては、後ほど詳細解説のセクションで探ります。*

一括更新はバッチパイプラインの根幹ですが、多くの実際のアプリケーションでは頻繁な単一行の更新に依存しています。そこでの比較を見てみましょう。


## 単一行の更新

**ReplacingMergeTree** や **CoalescingMergeTree** に適したワークロードを表現するため、**単一行の更新**もベンチマークしました。


* 先ほどの **10 個の更新** はそれぞれ、(数千行ではなく) **1 行**を対象にするよう変更されています。
[SQL ファイルを見る →](https://github.com/ClickHouse/examples/tree/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/10x1)

* **ReplacingMergeTree** では更新ごとに新しい行を挿入し、更新されないカラムには既存の値を反復して入れます。
[Replacing による挿入 →](https://github.com/ClickHouse/examples/tree/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/10x1)

    * (**CoalescingMergeTree** を使えば更新されないカラムの反復は回避できますが、更新されるすべてのカラムが [Nullable](https://clickhouse.com/docs/ja/reference/data-types/nullable#storage-features) である必要があります。)


**注意:** ここでは、[第 1 回](https://clickhouse.com/ja/blog/updates-in-clickhouse-1-purpose-built-engines-jp) で取り上げた更新専用エンジンの代表として **ReplacingMergeTree** のみをベンチマークしました。**CoalescingMergeTree** や **CollapsingMergeTree** でも性能は同等になります。


**ReplacingMergeTree** の **UPDATE パフォーマンス** を他の手法と比較するため、**同じ 10 個の単一行更新** を**ミューテーション**、**オンザフライミューテーション**、および**軽量な更新** (パッチパートで実装された[標準 SQL の UPDATE 構文](https://www.w3schools.com/sql/sql_update.asp)) としても記述しました。
[SQL ファイルを見る →](https://github.com/ClickHouse/examples/tree/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/10x1)

<details class="metric-box">
  <summary>測定方法 – 単一行更新の実行時間 (クリックして展開)</summary>
  <p>
    単一行 (ポイント) 更新には<b>同じ手順</b>を使用しました:
    テーブルを <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/run_updates_sequential.sh#L84" target="_blank">DROP</a> して
    <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/run_updates_sequential.sh#L86" target="_blank">クローン</a>
    し、更新を
    <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/run_updates_sequential.sh#L103" target="_blank">適用</a>
    して実行時間を 3 回
    <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/run_updates_sequential.sh#L153" target="_blank">測定</a>
    して平均を算出します。これを
    <b>手法ごとに 10 回の更新</b> で繰り返しました。
  </p>
</details>

### 単一行 (ポイント) 更新がクエリから参照可能になるまでの時間

一括更新と同様に、10 個の単一行 (ポイント) UPDATE それぞれについて、次のグラフは 4 つの手法すべてで **UPDATE を発行してからその変更がクエリから参照可能になるまでの経過時間** を示しています。

また、影響を受けるすべてのデータパートが書き換えられた後にのみ可視化される従来のミューテーションのベースラインと比較して、**軽量な更新と Replacing による挿入がどれだけ高速か (% 表示)** も示しています。

<details class="metric-box metrics">
  <summary>グラフ内のその他の主要指標 (クリックして展開)</summary>
  <div class="metric-row"><div class="metric-label">Rows upd / Cols upd</div><div class="metric-value">UPDATE の対象となった行数とカラム数</div></div>
  <div class="metric-row"><div class="metric-label">Full cols size</div><div class="metric-value">従来のミューテーションが書き換えるバイト数</div></div>
  <div class="metric-row"><div class="metric-label">Upd data size</div><div class="metric-value">軽量な更新によって実際に書き込まれたバイト数</div></div>
</details>

![Blog-updates Part 3.003.png](https://cms.clickhouse-dev.com:1337/uploads/Blog_updates_Part_3_003_a1a6769c68.png)

* **オンザフライミューテーション** → 更新式がメモリに保持されるだけなので即座に可視化され (~0.03 秒)、完全な書き換えは後からバックグラウンドで行われます。

* **ReplacingMergeTree による挿入** → 新しい行のみを書き込むため未加工の速度としては最速 (0.03〜0.04 秒) で、完全なミューテーションと比較して最大 **4,700 倍高速** です。行の検索は一切行われませんが、その後のクエリではバックグラウンドマージが完了するまで複数の行バージョンを解決する必要があります。

* **軽量な更新** → ほぼ同等の速さ (0.04〜0.07 秒) で、完全なミューテーションと比較して最大 **2,400 倍高速** であり、極小のパッチパートを書き込みます。行のルックアップが発生するためわずかに遅くなりますが、クエリ実行時の効率ははるかに高くなります。

* **ミューテーション** → たった 1 行であっても影響を受けるすべてのカラムを書き換えるため、最も低速です (90〜170 秒)。

[生のベンチマーク結果はこちら →](https://github.com/ClickHouse/examples/tree/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/results)

*一括更新の結果と同様に、こうした傾向の理由は後ほど詳細解説で説明します。*

繰り返しになりますが、更新速度は全体の一面にすぎません。単一行の更新はクエリにどう影響するでしょうか。


### 更新後の最悪条件下でのクエリ時間 — 単一行の更新

単一行のベンチマークでは、複数行のテストと**同じ [10 個の分析クエリ](https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/10x1/analytical_queries.sql)** を再利用しています。

このセクションでは、一括更新のテストと同様に、ディスク上で変更が完全に実体化される前に更新されたばかりの行にヒットするクエリの所要時間である**更新後の最悪条件下でのクエリ時間**をベンチマークし、従来のミューテーションが更新を完全に実体化させた後の同じクエリの実行時間 (ベースライン) と比較した速度低下率 (%) を報告します。

<details class="metric-box">
  <summary>測定方法 – ポイント更新後の最悪条件下でのクエリ時間 (クリックして展開)</summary>
  <p>• 各クエリはその更新と 1 対 1 で対応しており、3 回の実行にわたる<b>平均実行時間とメモリ</b>を <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/run_updates_sequential.sh#L153" target="_blank">記録</a> します。</p>
  <div class="notes">
    <b>注意:</b><br>
    • <b>各クエリは少なくとも更新された行とカラムを読み取ります</b>が、現実的な分析を想定してより広範なデータをスキャンするものも多くあります。<br>
    • <b>最悪条件のレイテンシ</b>を捉えるため、ベンチマークでは
    <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/run_updates_sequential.sh#L99" target="_blank">バックグラウンドマージを無効化</a> しています:<br>
    <div style="margin-left:20px;margin-top:4px;">
      • <b>オンザフライミューテーション</b> は純粋にメモリ内にとどまります。<br>
      • <b>軽量な更新</b> は Patch-on-read (暗黙的な FINAL) に依存します。<br>
      • <b>ReplacingMergeTree</b> クエリは <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/run_updates_sequential.sh#L148" target="_blank">明示的な FINAL</a> を付けて実行されます。
    </div>
  </div>
</details>

次のグラフは、完全に実体化された更新のベースラインと比較した、各タイプの一括 UPDATE 後における [10 個の分析クエリ](https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/10x1/analytical_queries.sql) 全部の**更新後の最悪条件下でのクエリ時間**を示しています:

<details class="metric-box metrics">
  <summary>グラフ内のその他の主要指標 (クリックして展開)</summary>
  <div class="metric-row"><div class="metric-label">Slowdown %</div><div class="metric-value">完全に実体化された (ミューテーション) ベースラインに対する追加の実行時間</div></div>
  <div class="metric-row"><div class="metric-label">Memory (MiB)</div><div class="metric-value">クエリによって使用されたピークメモリ</div></div>
  <div class="metric-row"><div class="metric-label">Memory Δ (%)</div><div class="metric-value">ベースラインに対するメモリ使用量の変化率</div></div>
</details>

![Blog-updates Part 3.004.png](https://cms.clickhouse-dev.com:1337/uploads/Blog_updates_Part_3_004_b700981c01.png)

* **従来のミューテーション (ベースライン)** → 同期ミューテーションがディスク上の影響を受けるデータパートを完全に書き換えた後のクエリ実行時間。

* **軽量な更新** → クエリに対して最も効率的で、速度低下は 7〜18% (平均 ~12%)、メモリ増加は +20%〜210% です。*グラフの見やすさを保つため、**ファストマージモード** のみを表示しています。*

* **オンザフライミューテーション** → 即座に可視化され、ReplacingMergeTree + FINAL よりも高速な場合が多いですが、メモリ内に多くの更新がたまると急激に遅くなります (ここでは図示していません)。

* **ReplacingMergeTree + FINAL** → 最も負荷の高いクエリとなり、クエリがすべての行バージョンを読み取る必要があるため、速度低下は 21〜550% (平均 ~280%)、メモリはベースラインの 20 倍〜200 倍になります。

*[生のベンチマーク結果はこちら →](https://github.com/ClickHouse/examples/tree/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/single-row-updates/results)*

結果は極めて顕著です。では、ClickHouse がなぜこのような振る舞いをするのか、内部の仕組みを覗いてみましょう。


## 詳細解説: 結果がこのようになる理由

第 [1](https://clickhouse.com/ja/blog/updates-in-clickhouse-1-purpose-built-engines-jp) 回と第 [2](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp) 回では、従来のミューテーション、軽量な更新、ReplacingMergeTree などの専用エンジンといった、各更新手法が内部でどのように動作するかをすでに解説しました。

ここではさらに一歩踏み込み、これらの手法を並べて比較することで、ベンチマークのグラフがなぜこのような形になったのか、そして ClickHouse の内部で実際に何が起きているのかを明らかにします。


### 軽量な更新が挿入のように感じられる理由

> その名称にかかわらず、これらは通常の [SQL UPDATE ステートメント](https://www.w3schools.com/sql/sql_update.asp) です。ClickHouse はカラム全体を書き換える代わりにパッチパートを書き込むことで、それらを最適化しています。

[軽量な更新は、カラム全体を書き換える代わりに極小のパッチパートを書き込み](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)ます。

[クエリ実行時には、メモリ上でこれらのパッチを重ね合わせるだけ (patch-on-read)](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp) であるため、小さな変更の適用は新しい行を挿入するのとほぼ同等の速度に感じられます。

具体的には、軽量な更新が書き出すパッチパートには以下のみが含まれます:

* **更新された値**
* ごく少量の**[対象指定メタデータ](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)**: _part、_part_offset、_block_number、_block_offset、および _data_version

このメタデータは更新が必要な行を**正確に**指し示すため、ClickHouse は関係のないデータをスキャンしたり書き換えたりすることを回避できます。

更新のパフォーマンスは、変更された値と対象行のメタデータのみを書き込む [INSERT INTO … SELECT](https://clickhouse.com/docs/ja/reference/statements/insert-into#inserting-the-results-of-select) とおおよそ同等です:
<pre>
<code type='click-ui' language='sql' show_line_numbers='false'>
-- 軽量な更新ステートメント:

UPDATE lineitem
SET l_discount = 0.045, l_tax = 0.11, ...
WHERE l_commitdate = '1996-02-01' AND l_quantity = 1;
</code>
</pre>
≈
<pre>
<code type='click-ui' language='sql' show_line_numbers='false'>
-- おおよそ同等の処理:

INSERT INTO patch
SELECT 0.045 as l_discount, 0.11 as l_tax, ...,
       _part, _part_offset, _block_number, _block_offset
FROM lineitem
WHERE l_commitdate = '1996-02-01' AND l_quantity = 1;
</code>
</pre>

軽量な更新が小さな挿入と同じくらい高速に感じられるのは、無関係なデータのスキャンや書き換えを行わないためです。

> そのメカニズムは意図的に ClickHouse の高速かつ効率的な挿入の仕組みに基づいているため、**挿入を実行できるのと同じくらいの頻度で軽量な更新を実行できます**。


### 軽量な更新を使用すべき場合 (および使用すべきでない場合)

> **軽量な更新は、頻繁で小さな変更 (テーブルの ≈ 10% 以下) 向けに設計されています**。<br/>[更新後の最悪条件](/ja/blog/updates-in-clickhouse-3-benchmarks-jp)でのクエリ速度低下をほとんど発生させず、更新をほぼ瞬時に反映させたい場合に使用してください。

軽量な更新は、一度にテーブルの数パーセントを更新するような、**小さく頻繁な修正**で威力を発揮します。

しかし、大規模な更新を行うと**巨大なパッチパート**が作成され、以下のような問題が生じます:

* マージされるまで**すべてのクエリ実行時にメモリ上で適用** ([patch-on-read](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)) しなければならない。

* 実体化されるまでの間、**CPU と RAM のオーバーヘッド**が増大する。

* **最終的にはソースパートへマージ**されることになる。

**大規模な変更**の場合、次回の定期バックグラウンドマージでパッチが実体化されるまでの間、クエリが大幅に遅くなる可能性があります。
その場合は、[従来のミューテーション](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)を実行し、**1 回だけ**長く待って (更新によってパートを書き換え)、その後に**ベースラインのクエリパフォーマンス**を享受する方が**適している**ことがよくあります。


> 軽量な更新は**付箋**のようなものだと考えてください。素早く正確な編集には最適です。
**しかし、壁全体を張り替えるのであれば、新しい壁紙を貼る (ミューテーション) 方が高速で綺麗に仕上がります。**

このトレードオフを視覚化するために、2 つの概略図を用意しました。


#### 図 1 – 更新レイテンシ

図 1 は、変更される行の割合が増加するにつれて更新レイテンシがどのように変化するかを示しています。

![Blog-updates Part 3.007.png](https://cms.clickhouse-dev.com:1337/uploads/Blog_updates_Part_3_007_1697d78f3d.png)

* **ミューテーション (灰色の線)** は影響を受けるすべてのカラムを書き換えるため、レイテンシは一定のままです。

* **軽量な更新 (黄色の線)** はパッチパートのみを書き込むため、極小の変更では最も高速ですが、更新がテーブルのより広い範囲に及ぶにつれてミューテーションのレイテンシに徐々に近づいていきます。

#### 図 2 – 一括更新後のクエリ実行時間

図 2 は、一括 (複数行) 更新の後、更新が完全に実体化される前に代表的なクエリがどれだけ遅くなるかを推定したものです。

![Blog-updates Part 3.008.png](https://cms.clickhouse-dev.com:1337/uploads/Blog_updates_Part_3_008_a384ebe49b.png)

* **同期ミューテーション**では、クエリが実行される**前**にデータパートが書き換えられるため、実行時間は一定のままです。

* **patch-on-read** では、ClickHouse が実行**中**にパッチパートを重ね合わせます。パッチが大きくなるにつれて、クエリは比例して遅くなります。

**そのため、小規模で頻繁な一括変更 (テーブルの最大約 10% まで) には軽量な更新を使用してください:** patch-on-read はパッチパートが大きくなるにつれてクエリの低下をもたらしますが、バックグラウンドマージが完了すればベースラインのパフォーマンスに戻ります。それ以上の規模の変更には、従来の (同期) ミューテーションを使い続けてください。



### patch-on-read のモード: 高速モードと結合フォールバック

今回のデータセットにおいて、パッチパートが**[高速マージモード](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)の patch-on-read** (元のソースパートがまだ存在している状態) で適用された場合、速度低下は **8% 〜 21%** の範囲にとどまり、**平均は 15.3%** であったことを[前述](/ja/blog/updates-in-clickhouse-3-benchmarks-jp)しました。

[第 2 回](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)で説明したように、次回のバックグラウンドマージによってパッチが最終的に実体化されるときも、そのマージが発生する前にクエリが実行されて patch-on-read 経由で**メモリ上**に適用されるときも、ほとんどの場合は**パッチのソースパートがまだ存在しています**。

ごくまれに、**無害なタイミングの重複**が発生することがあります。パッチパートは **UPDATE 開始時点のソースパートの[スナップショット](https://clickhouse.com/blog/clickhouse-release-25-06#single-snapshot-for-select)**に対して作成されますが、パッチの書き込みと**並行してそれらのパートがマージ**された場合、そのパッチは (高速マージモードの patch-on-read において) アクティブでなくなったソースパートを対象にすることになります。

その場合、ClickHouse は**自動的に**、**[より低速な結合モード](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)の patch-on-read** に**フォールバック**します。[前述](/ja/blog/updates-in-clickhouse-3-benchmarks-jp)のとおり、このモードのオーバーヘッドはより高く、今回のベンチマークでは **39% 〜 121%**、平均 **68%** でした。このモードは、パッチとマージ済みデータの間で**インメモリ結合**を実行します。

<details class="metric-box">
  <summary>測定方法 – より低速な結合モードの patch-on-read (クリックして展開)</summary>
  <p>
    このシナリオを明示的に測定するために、
    <a href="https://clickhouse.com/docs/ja/reference/settings/merge-tree-settings" target="_blank">
      apply_patches_on_merge
    </a>
    を
    <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/run_updates_sequential.sh#L121" target="_blank">
      無効
    </a>
    にした状態で、
    <a href="https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/run_updates_sequential.sh#L126" target="_blank">
      テーブルの単一データパートの自己マージを強制
    </a>
    しました。
    マージによってパートが新しい名前で書き換えられたため、パッチの
    <a href="https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp" target="_blank">
      ソースインデックス
    </a>
    が無効化され、クエリ実行時により低速な結合モードへのフォールバックがトリガーされました。
  </p>
</details>


### ReplacingMergeTree の挿入が生の速度で優れている理由

ReplacingMergeTree は[更新を新しい行の挿入としてモデル化](https://clickhouse.com/ja/blog/updates-in-clickhouse-1-purpose-built-engines-jp)し、ディスクには新しい行のみを書き込みます。



* 古い行を見つけるための**検索 (ルックアップ) が不要**であり、これが実質的に最速の更新方法となっています。

* 今回のベンチマークでは、更新は通常 **0.03 〜 0.04 秒**で完了し、従来のミューテーションと比べて最大 **4,700 倍高速**でした。


#### 軽量な更新もほぼ同等に高速

単一行の (ポイント) UPDATE では、軽量な更新はディスクに**ごくわずかなパッチパート** (多くの場合、数十バイト程度) のみを書き込みます。



* まず、ClickHouse は元のパート内で**更新対象の行を特定**し、その[ターゲットメタデータ](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp) (_part、_part_offset、_block_number、_block_offset、_data_version) を生成します。

* その後、**更新された値**とその小さなメタデータパッチのみを書き込みます。


この追加の検索処理により、軽量な更新は ReplacingMergeTree の挿入よりも**わずかに遅く**なりますが、patch-on-read はどの行を重ね合わせるべきかを正確に把握しているため、**クエリ実行時の効率は大幅に向上**します。

次のセクションでは、この挙動を ReplacingMergeTree の仕組みと比較します。


### FINAL が patch-on-read よりも遅い理由

> [FINAL](https://clickhouse.com/ja/blog/updates-in-clickhouse-1-purpose-built-engines-jp) クエリは最新の行を**見つけ出す**必要がありますが、[patch-on-read](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp) クエリはそれらの行がどこにあるかを**すでに知っています**。


#### 違いを示す 2 つの簡易図

**図 1 – FINAL:** ClickHouse はどのパートに最新の行があるかを判別*できない*ため、パートを読み込み、メモリ上でその場で[マージ](https://clickhouse.com/docs/ja/concepts/core-concepts/merges#replacing-merges)し、[クエリエンジン](https://clickhouse.com/docs/ja/concepts/core-concepts/query-parallelism)がデータをさらに処理する前にソートキーごとに最新の行のみを保持します。

![Blog-updates Part 3.005.png](https://cms.clickhouse-dev.com:1337/uploads/Blog_updates_Part_3_005_9f0a05cc39.png)

ここでは詳細には触れませんが、FINAL のマージ処理は近年大幅に[最適化](https://clickhouse.com/blog/clickhouse-release-23-12#optimizations-for-final)されています。また、FINAL 処理中に必要な作業量を最小限に抑えるための[ベストプラクティス](https://clickhouse.com/docs/ja/concepts/features/operations/update/replacing-merge-tree#exploiting-partitions-with-replacingmergetree)も存在します。

**図 2 – patch-on-read:** パッチパートによって ClickHouse はどの行が変更されたかを*正確に*把握できるため、メモリ上でその場でそれらの行のみを[重ね合わせ](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)ます。広範囲に及ぶマージは必要ありません。
![Blog-updates Part 3.006.png](https://cms.clickhouse-dev.com:1337/uploads/Blog_updates_Part_3_006_b83131702c.png)

パッチパートは _part、_part_offset、_block_number、_block_offset を介してターゲット行を正確に参照するため、**極めてピンポイントで的を絞った重ね合わせ**が可能になります。


#### クイックサマリー表

| FINAL (ReplacingMergeTree) | patch-on-read (軽量な更新) |
|---------------------------|-------------------------------------|
| どのパートに最新バージョンの行が含まれているかを**把握していない**。 | どの行が更新され、どこに保存されているか (パッチパート) を**正確に把握している**。 |
| すべてのパートにわたって**すべての候補範囲をマージ**し、ソートキーと挿入時間に基づいて最新バージョンを解決しなければならない。 | パッチパートが _part、_part_offset、_block_number、_block_offset を介して**更新対象の行を直接参照**する。 |
| 行バージョンの解決が**広範囲かつ探索的**であり、負荷の高い処理を必要とする。 | マージが**ピンポイントかつ的を絞った**ものであり、把握済みの更新行のみを重ね合わせる。 |
| 歴史的に通常の読み取りよりも大幅に遅かった。現在は大幅に最適化されているものの、依然として patch-on-read より重い。 | 非常に効率的で軽量、かつ予測可能。 |

仕組みが明確になったところで、すべてをまとめる簡単な比較の振り返りを示します。

## UPDATE 手法の概要

*まとめる前に、各 UPDATE 手法の一覧比較を示します:*

* **従来のミューテーション** — 最も遅い経路。クエリが新しいデータを参照できるようになる前に、ディスク上のカラム全体を書き換える。

* **オンザフライミューテーション** — 即時。更新式をメモリに保持するため、クエリは遅くなる。

* **ReplacingMergeTree の挿入** — 書き込みは高速だが、FINAL によるクエリのオーバーヘッドが増加する。

* **軽量な更新** — INSERT とほぼ同じくらい高速でありながら、クエリへの影響を低く抑えられる。


**チートシート:** 各更新手法の強みと、それに伴うコストは以下のとおりです。

| 手法 | 最適な用途 | 最悪条件でのクエリへの影響 | 注意点 |
|----------------------------------|---------------------------------------------------|---------------------|----------------------------------------------------------------|
| ミューテーション | 大規模で頻度の低い一括変更 | ベースライン | 適用に時間がかかる |
| オンザフライミューテーション | 即座の可視性が必要なアドホックの大規模変更 | ↑ 12 〜 427 % | **後からパートを書き換える処理は残る。** 多く重なるとクエリが遅くなる |
| ReplacingMT + FINAL | 高頻度な単一行の更新 | ↑ 21 〜 550 % | `FINAL` 句が必要 |
| 軽量な更新 (パッチパート) | 高頻度な小規模更新 (テーブルの 10% 以下) | ↑ 7 〜 21 % | ソースがマージによって消失した場合、より低速な結合モードになる |


仕組みが明確になり、横並びの結果が得られたところで、これが実際のワークロードにとって何を意味するのかをまとめます。



## まとめ: 1,000 倍高速な ClickHouse の UPDATE

ClickHouse は**標準 SQL の UPDATE** に対応しました。これは**パッチパートを用いた軽量な更新**として実装されており、列指向ストアのパフォーマンスにおける長年の課題を解決するアプローチです。

今回のベンチマーク結果:

* **一括 SQL UPDATE** は従来のミューテーションより最大 **1,700 倍高速**

* **単一行の SQL UPDATE** は最大 **2,400 倍高速**

* これらすべてをわずかな (最悪条件下の) クエリオーバーヘッドのみで実現

これが意味すること:

* 使い慣れた SQL 構文を使用した、クエリを遅くさせない**高頻度な小規模更新**

* リアルタイムおよびストリーミングワークロード向けの**即座に可視化される変更**

* バッチ更新とインタラクティブな更新をシームレスに混在させられる**スケーラブルなパイプライン**


ClickHouse は、分析ワークロードにおいて優れた性能を維持しながら、従来は行指向ストア専用とされていた更新パターンも処理できるようになりました。

*[すべてのベンチマークスクリプトとクエリは GitHub で公開されています](https://github.com/ClickHouse/examples/tree/main/blog-examples/clickhouse-fast-updates)。*

これで、ClickHouse 列指向ストア向けの高速な UPDATE 構築に関する **3 回シリーズ**は完結となります。<br/>過去の記事をまだご覧になっていない方は、[第 1 回: 専用に設計されたエンジン](https://clickhouse.com/ja/blog/updates-in-clickhouse-1-purpose-built-engines-jp)と[第 2 回: SQL スタイルの UPDATE](https://clickhouse.com/ja/blog/updates-in-clickhouse-2-sql-style-updates-jp)をぜひご確認ください。