---
# System prepended metadata

title: ClickHouse 是什麼？一個新手的學習與實作紀錄
tags: [Database]

---

# ClickHouse 是什麼？一個新手的學習與實作紀錄

### 引言
近期在工作上開始需要接觸 **ClickHouse**，但對我來說這是一個完全陌生的資料庫系統。過去大多使用的是 Relational Database (關聯式資料庫)，對於 ClickHouse 這類主打高效能分析查詢的 OLAP（線上分析處理）Database，其實並沒有太多實務經驗。

因此撰寫這篇文章，一方面是作為自己學習 ClickHouse 的紀錄，另一方面也希望透過「寫出來」的方式，幫助自己更好地理解與內化相關概念。

本文內容將以新手角度出發，著重在 ClickHouse 的基本概念、使用情境與實際操作體驗，不會深入過於底層或艱澀的實作細節。如果你也正準備第一次接觸 ClickHouse，希望這篇文章能成為一個友善的入門起點。

### Why? Why we use this cool stuff？

這邊不免俗的先說一下官方對這個產品的應用場景

1. 實時分析
2. 可觀察性
3. 作為資料庫
4. 機器學習和生成式 AI

簡單來說，ClickHouse 最擅長處理的是 **需要高速分析和查詢大規模資料** 的場景

#### 那他的大規模是多大呢？
他的官方文件在 Abstract 的地方提及他可以處理 PB 級 (Petabyte, 千兆 byte) 的資料量

> This paper presents an overview of ClickHouse, a popular opensource OLAP database designed for high-performance analytics over petabyte-scale data sets with high ingestion rates.
> [ClickHouse Architecture Overview](https://clickhouse.com/docs/academic_overview?utm_source=chatgpt.com)
> 取自 Abstract

### What? What is ClickHouse?

在我們進入主題之前，必須先釐清兩個經常被一起提到、但用途完全不同的概念：
OLTP 與 OLAP。

#### What is OLTP?
> OLTP 
> Online Transaction Precessing, 線上交易處理
是我們日常開發中最熟悉的資料庫使用情境

他的特點是:
- 高頻率、短時間的操作
- 以 新增（INSERT）/ 更新（UPDATE）/ 刪除（DELETE） 為主
- 通常只影響少量資料
- 強調交易正確性與一致性（ACID）

像 MySQL、PostgreSQL、MSSQL 這類傳統的 Relational DB，大多都是針對 OLTP 場景進行最佳化設計 
> Relational DB 可以同時支援 OLTP 和 OLAP，只是通常來說是 OLTP

#### What is OLAP?
> OLAP
> Online Analytical Processing, 線上分析處理
> 它描述的是一種針對大量資料做複雜查詢與分析的方式，而不是一般的交易式查詢。

OLAP 關心的不是「單筆資料是否成功寫入」，而是：
- 對 大量歷史資料 進行查詢
- 複雜的聚合、統計與分群分析
- 查詢時會掃描大量資料，但寫入相對較少
- 目的是產生報表、洞察趨勢或分析結果

#### OLTP V.S. OLAP

> OLTP 關心的是「一筆資料快不快、準不準」
> OLAP 關心的是「一大堆資料算得快不快」

雖然傳統 relational database 理論上可以同時支援 OLTP 與 OLAP，但在實務上：

- 當資料量變大
- 查詢變得複雜（大量 GROUP BY / 聚合）
- 分析需求頻繁出現

OLAP 查詢往往會：
- 變得非常慢
- 影響原本的交易系統效能

| 項目 | OLTP | OLAP |
|---|---|---|
| 主要目的 | 處理日常交易與即時操作 | 分析大量歷史資料、產生報表與洞察 |
| 常見操作 | INSERT / UPDATE / DELETE | SELECT（大量聚合、統計、分群） |
| 查詢特性 | 短、快速、影響資料量小 | 複雜、耗資源、掃描大量資料 |
| 資料量 | 相對較小（單筆或少量資料） | 非常大（百萬、億級甚至以上） |
| 寫入頻率 | 高頻率寫入 | 寫入較少，讀取為主 |
| 查詢延遲需求 | 極低（毫秒等級） | 可接受較高延遲，但仍希望快 |
| 資料結構 | 高度正規化（Normalization） | 常為反正規化（Denormalization） |
| 儲存方式 | 多為行式儲存（Row-oriented） | 多為列式儲存（Column-oriented） |
| 典型使用情境 | 使用者登入、下單、付款 | 報表、趨勢分析、指標計算 |
| 常見資料庫 | MySQL、PostgreSQL、Oracle | ClickHouse、BigQuery、Redshift |

> 也就是說，當我們的需求從「穩定處理交易」轉向「快速分析大量資料」時，
就需要一種在設計上就為 OLAP 最佳化的資料庫。
>
> ClickHouse，正是在這樣的背景下誕生的。

#### What is ClickHouse?

在了解 OLAP 的概念之後，其實 ClickHouse 是什麼也就呼之欲出了。

**ClickHouse 就是一個專門用來「快速分析大量資料」的資料庫。**

當你的需求是：
- 對大量歷史資料做統計與分析
- 常常需要 `GROUP BY`、聚合、指標查詢
- 查詢效能開始成為瓶頸

那麼 ClickHouse，通常就是一個很合理的選擇。

ClickHouse 並不是要取代原本的 relational database，
而是用來處理 **OLAP（分析型）** 的需求，讓交易系統可以專心做好 OLTP。

### How? How can I connect to ClickHouse?

> 本篇文章是以 C# 作為範例，也可以去看看官方文件其他語言是怎麼連的
> [Language Client](https://clickhouse.com/docs/integrations/language-clients)

首先我們要在 proj 裡新增 ClickHouse.Driver 這個 package
```
dotnet add package ClickHouse.Driver
```

也可以使用 NuGet

```
Install-Package ClickHouse.Driver
```

要連接到 ClickHouse，官方文件推薦使用 ClickHouseConnection
下面是最基本的連線範例

#### 連到 ClickHouse
```
using ClickHouse.Driver.ADO;

using var connection = new ClickHouseConnection(
    "Host=localhost;Port=8123;Database=default;Username=default;Password=mypassword;Protocol=http"
);

await connection.OpenAsync();
```

`Host`: ClickHouse Server location
`Username`, `Password`: 登入帳密

我這邊透過 docker 已經運行起 ClickHouse 了
可以參考我的 `docker.compose.yaml`

```
version: '3.8'
services:
  clickhouse:
    image: clickhouse/clickhouse-server:latest
    container_name: clickhouse-server
    environment:
      CLICKHOUSE_DB: clickhousedemo
      CLICKHOUSE_USER: default
      CLICKHOUSE_PASSWORD: mypassword
    ports:
      - "8123:8123"
      - "9000:9000"
    ulimits:
      nofile:
        soft: 262144
        hard: 262144
    volumes:
      - clickhouse_data:/var/lib/clickhouse

volumes:
  clickhouse_data:
```

#### 建立 Table 
```
var createTable = @"
CREATE TABLE IF NOT EXISTS demo_logs
(
    timestamp DateTime,
    service String,
    latency_ms UInt32
)
ENGINE = Memory";

using (var cmd = connection.CreateCommand())
{
    cmd.CommandText = createTable;
    await cmd.ExecuteNonQueryAsync();
}
```

#### INSERT 一筆資料

```
using (var insert = connection.CreateCommand())
{
    insert.CommandText = "INSERT INTO demo_logs (timestamp, service, latency_ms) VALUES (now(), 'demo_service_1', 123)";
    await insert.ExecuteNonQueryAsync();
}
```

#### INSERT 多筆資料

```
using (var insertMany = connection.CreateCommand())
{
    insertMany.CommandText = @"
        INSERT INTO demo_logs (timestamp, service, latency_ms) VALUES
        (now(), 'demo_service_2', 456),
        (now(), 'demo_service_3', 78),
        (now(), 'demo_service_4', 90)";
    await insertMany.ExecuteNonQueryAsync();
}
```

#### 基礎的 SELECT 語法

```
using (var select = connection.CreateCommand())
{
    select.CommandText = "SELECT timestamp, service, latency_ms FROM demo_logs";
    using var reader = await select.ExecuteReaderAsync();
    Console.WriteLine("Query Result : ");
    while (await reader.ReadAsync())
    {
        var timestamp = reader.GetFieldValue<DateTime>(0);
        var service = reader.GetFieldValue<string>(1);
        var latency = reader.GetFieldValue<uint>(2);
        Console.WriteLine($"[{timestamp}] Service: {service}, Latency: {latency} ms");
    }
}
```

#### UPDATE and DELETE 資料
> ClickHouse 是針對 OLAP，所以不像 MySQL 那樣適合頻繁更新或刪除單筆資料

```
// UPDATE
using (var update = connection.CreateCommand())
{
    update.CommandText = @"
        ALTER TABLE demo_logs 
        UPDATE latency_ms = 200 
        WHERE service = 'demo_service_1'";
    await update.ExecuteNonQueryAsync();
}

// DELETE
using (var delete = connection.CreateCommand())
{
    delete.CommandText = @"
        ALTER TABLE demo_logs
        DELETE WHERE service = 'demo_service_4'";
    await delete.ExecuteNonQueryAsync();
}
```


### 結語

ClickHouse 的核心價值在於 **快速分析大資料**，在 OLAP 場景中非常強大，但設計上偏向 **讀取與分析**，不適合做頻繁單筆更新
