ติดตั้ง ClickHouse ฐานข้อมูล analytics บน VPS

ติดตั้ง ClickHouse บน VPS ฐานข้อมูลวิเคราะห์ความเร็วสูง

กันยายน 2026 · อ่าน 10 นาที

ClickHouse คือฐานข้อมูลแบบ columnar (column-oriented) ที่พัฒนาโดย Yandex ออกแบบมาเพื่องาน analytics โดยเฉพาะ สามารถ query ข้อมูลหลายพันล้านแถวได้ในเวลาไม่กี่วินาที บน VPS ทั่วไป ต่างจากฐานข้อมูล relational ทั่วไปที่เก็บข้อมูลเป็น row ClickHouse เก็บแต่ละคอลัมน์แยกกัน ทำให้ query เฉพาะคอลัมน์ที่ต้องการได้เร็วมาก ใช้ storage น้อยลงด้วย compression ขั้นสูง เหมาะสำหรับ log analytics, web analytics, time-series data, business intelligence และทุกงานที่ต้องการ aggregate ข้อมูลขนาดใหญ่

ความต้องการของระบบ

ขั้นต่ำแนะนำ
RAM 2 GBRAM 8 GB+
CPU 2 coresCPU 4+ cores
Disk 20 GB SSDDisk 100 GB+ NVMe
Ubuntu 22.04 / Debian 12Ubuntu 24.04 LTS

ติดตั้ง ClickHouse บน Ubuntu/Debian

# เพิ่ม ClickHouse official repository
sudo apt install -y apt-transport-https ca-certificates curl gnupg

curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg] https://packages.clickhouse.com/deb stable main" \
  | sudo tee /etc/apt/sources.list.d/clickhouse.list

sudo apt update
sudo apt install -y clickhouse-server clickhouse-client

ระหว่างติดตั้งระบบจะถามรหัสผ่าน default user (default) ให้ตั้งรหัสผ่านแข็งแรง หรือกด Enter เพื่อปล่อยว่างไว้ก่อน (ไม่แนะนำบน production)

เริ่มต้นใช้งาน ClickHouse

# เริ่ม service
sudo systemctl start clickhouse-server
sudo systemctl enable clickhouse-server

# ตรวจสอบ status
sudo systemctl status clickhouse-server

# เชื่อมต่อด้วย clickhouse-client
clickhouse-client --password

สร้าง Database และ Table แรก

-- สร้าง database
CREATE DATABASE myanalytics;
USE myanalytics;

-- สร้าง table สำหรับเก็บ web access log
CREATE TABLE access_log (
    event_time   DateTime,
    client_ip    IPv4,
    http_method  LowCardinality(String),
    request_uri  String,
    status_code  UInt16,
    bytes_sent   UInt32,
    response_ms  UInt32
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(event_time)
ORDER BY (event_time, client_ip);

-- ดู schema
DESCRIBE TABLE access_log;
Tip: MergeTree คือ engine หลักของ ClickHouse รองรับ data partitioning และ sorting ทำให้ query range เร็วมาก ใช้ PARTITION BY toYYYYMM() แบ่งข้อมูลตามเดือน เพื่อลด scan เมื่อ query ตามช่วงเวลา

INSERT และ Query ข้อมูล

-- ใส่ข้อมูลตัวอย่าง
INSERT INTO access_log VALUES
    (now(), '203.0.113.5', 'GET', '/index.html', 200, 1024, 45),
    (now(), '198.51.100.2', 'POST', '/api/login', 200, 512, 120),
    (now(), '192.0.2.10', 'GET', '/static/app.js', 304, 0, 8);

-- นับ request ตาม status code
SELECT status_code, count() AS hits, avg(response_ms) AS avg_ms
FROM access_log
GROUP BY status_code
ORDER BY hits DESC;

-- Top 10 URI ที่มี request มากสุด
SELECT request_uri, count() AS cnt
FROM access_log
GROUP BY request_uri
ORDER BY cnt DESC
LIMIT 10;

ตั้งค่า User และสิทธิ์

-- สร้าง user ใหม่ที่มีสิทธิ์จำกัด
CREATE USER analyst IDENTIFIED WITH sha256_password BY 'SecurePass!2026';

-- ให้สิทธิ์อ่านอย่างเดียวในฐานข้อมูล myanalytics
GRANT SELECT ON myanalytics.* TO analyst;

-- สร้าง user สำหรับ app ที่ insert ข้อมูลได้
CREATE USER app_writer IDENTIFIED WITH sha256_password BY 'AppWrite!2026';
GRANT INSERT ON myanalytics.* TO app_writer;

-- ดู users ทั้งหมด
SHOW USERS;

Materialized View สำหรับ Pre-aggregate

-- สร้าง summary table
CREATE TABLE hourly_stats (
    hour         DateTime,
    status_code  UInt16,
    request_cnt  UInt64,
    avg_ms       Float32,
    total_bytes  UInt64
) ENGINE = SummingMergeTree()
ORDER BY (hour, status_code);

-- สร้าง Materialized View ที่คำนวณอัตโนมัติ
CREATE MATERIALIZED VIEW mv_hourly_stats
TO hourly_stats
AS SELECT
    toStartOfHour(event_time) AS hour,
    status_code,
    count()          AS request_cnt,
    avg(response_ms) AS avg_ms,
    sum(bytes_sent)  AS total_bytes
FROM access_log
GROUP BY hour, status_code;

-- Query จาก pre-aggregated table (เร็วมาก)
SELECT hour, sum(request_cnt), avg(avg_ms)
FROM hourly_stats
GROUP BY hour
ORDER BY hour DESC
LIMIT 24;
Tip: Materialized View อัปเดตอัตโนมัติทุกครั้งที่มี INSERT ใหม่ เหมาะสำหรับ dashboard ที่ต้อง query บ่อยมาก ลด query time จาก raw table ได้หลายเท่า

ตั้งค่า Network Binding และ Firewall

# แก้ไข config ให้รับ connection จาก network
sudo nano /etc/clickhouse-server/config.xml

# หาและแก้ line นี้ (ค่า default คือ ::1 ฟังแค่ localhost)
# <listen_host>0.0.0.0</listen_host>   <!-- เปิดรับทุก IP -->
# หรือระบุ IP เฉพาะ:
# <listen_host>10.0.0.5</listen_host>

# อนุญาต port 8123 (HTTP) และ 9000 (native) ผ่าน UFW
sudo ufw allow from 10.0.0.0/8 to any port 8123
sudo ufw allow from 10.0.0.0/8 to any port 9000

# รีสตาร์ท ClickHouse
sudo systemctl restart clickhouse-server

Backup ด้วย clickhouse-backup

# ติดตั้ง clickhouse-backup
wget https://github.com/Altinity/clickhouse-backup/releases/latest/download/clickhouse-backup-linux-amd64.tar.gz
tar xzf clickhouse-backup-linux-amd64.tar.gz
sudo mv clickhouse-backup /usr/local/bin/

# สร้าง config
sudo mkdir -p /etc/clickhouse-backup
sudo clickhouse-backup default-config > /etc/clickhouse-backup/config.yml

# สร้าง backup
sudo clickhouse-backup create mybackup_$(date +%Y%m%d)

# ดู backup ที่มี
sudo clickhouse-backup list

# Restore
sudo clickhouse-backup restore mybackup_20260911

ตรวจสอบว่า ClickHouse ทำงานถูกต้อง

# ตรวจสอบ service status
sudo systemctl status clickhouse-server

# ทดสอบ HTTP API
curl http://localhost:8123/?query=SELECT+version()

# ทดสอบ native client
clickhouse-client --query "SELECT count() FROM system.tables"

# ดู running queries
clickhouse-client --query "SELECT query_id, elapsed, query FROM system.processes"

# ตรวจสอบ disk usage
clickhouse-client --query "
  SELECT database, table, formatReadableSize(sum(bytes_on_disk)) AS size
  FROM system.parts
  WHERE active
  GROUP BY database, table
  ORDER BY sum(bytes_on_disk) DESC
"
Tip: HTTP API port 8123 ใช้สำหรับ integration กับเครื่องมือภายนอกเช่น Grafana, Superset, Metabase Native port 9000 ใช้สำหรับ clickhouse-client และ driver ภาษา Go/Python/Java

แก้ปัญหาที่พบบ่อย

Error: "Code: 516. DB::Exception: default: Authentication failed"

รหัสผ่าน default user ไม่ถูกต้อง ให้ reset รหัสผ่านผ่าน config file

# แก้ไขรหัสผ่านใน users.xml
sudo nano /etc/clickhouse-server/users.d/default-password.xml

# ใส่ content นี้ (แทน password ด้วย hash SHA256)
# echo -n 'NewPassword' | sha256sum
<clickhouse>
  <users>
    <default>
      <password_sha256_hex>HASH_HERE</password_sha256_hex>
    </default>
  </users>
</clickhouse>

sudo systemctl restart clickhouse-server

Error: "DB::Exception: Too many parts (600). Merges are processing significantly slower"

เกิดจาก INSERT ข้อมูลบ่อยเกินไปในครั้งละน้อย ทำให้ parts สะสม ควร batch INSERT ให้ใหญ่ขึ้น

-- แทนที่จะ INSERT ทีละ row ให้ INSERT เป็น batch ใหญ่
INSERT INTO access_log SELECT * FROM input_buffer;

-- ตรวจดูจำนวน parts ปัจจุบัน
SELECT database, table, count() AS parts
FROM system.parts
WHERE active
GROUP BY database, table
ORDER BY parts DESC
LIMIT 10;

-- Force merge เพื่อลด parts (ใช้ resource สูง)
OPTIMIZE TABLE access_log FINAL;

Error: "Memory limit (for query) exceeded"

Query ใช้ RAM เกิน limit ที่ตั้งไว้ แก้ได้โดยเพิ่ม limit หรือ optimize query

-- เพิ่ม memory limit สำหรับ query นี้
SET max_memory_usage = 10000000000;  -- 10 GB

-- หรือแก้ใน users.xml
<max_memory_usage>10000000000</max_memory_usage>

-- ลด memory ใช้ด้วย sampling
SELECT count() FROM access_log SAMPLE 0.1;  -- ใช้แค่ 10%

Error: "Connection refused" บน port 8123

ClickHouse ฟังแค่ localhost หรือ service ไม่ทำงาน

# ตรวจสอบ ClickHouse ฟัง port อะไร
sudo ss -tlnp | grep clickhouse

# ตรวจสอบ config
grep -i listen /etc/clickhouse-server/config.xml

# ดู error log
sudo tail -50 /var/log/clickhouse-server/clickhouse-server.err.log

ข้อมูล query ช้ากว่าที่คาด

อาจเกิดจาก ORDER BY ไม่ตรงกับ query pattern หรือยังไม่มี materialized view

-- ดู query plan
EXPLAIN SELECT * FROM access_log WHERE client_ip = '203.0.113.5';

-- ดู query log เพื่อ profiling
SELECT query, read_rows, read_bytes, elapsed
FROM system.query_log
WHERE type = 'QueryFinish'
ORDER BY elapsed DESC
LIMIT 10;

คำถามที่พบบ่อย

ClickHouse ต่างจาก PostgreSQL หรือ MySQL อย่างไร?

PostgreSQL และ MySQL เป็น row-oriented database เหมาะกับ OLTP (Online Transaction Processing) เช่น web app ที่ INSERT/UPDATE/DELETE บ่อย ClickHouse เป็น column-oriented database เหมาะกับ OLAP (Online Analytical Processing) เช่น dashboard, report, analytics ที่ต้อง aggregate ข้อมูลหลาย column ในหลายล้านแถว ClickHouse ไม่รองรับ UPDATE/DELETE ตาม row ปกติ (ต้องใช้ ALTER TABLE ... DELETE ซึ่งช้ากว่า)

ClickHouse ใช้ RAM เยอะไหม?

โดยค่าเริ่มต้น ClickHouse ไม่มี cache daemon แบบถาวรเหมือน Redis แต่ใช้ page cache ของ OS ขณะ query สำหรับ production จริงควรมี RAM อย่างน้อย 8 GB แต่สำหรับ dev/test หรือ dataset ขนาดเล็กกว่า 100M rows ใช้ RAM 2-4 GB ก็พอได้

ClickHouse รองรับ SQL มาตรฐานไหม?

รองรับ SQL ส่วนใหญ่ใกล้เคียงมาตรฐาน ANSI SQL มี JOIN, subquery, window function, CTE ครบ แต่มี syntax บางอย่างต่างออกไป เช่น count() แทน COUNT(*), array functions เพิ่มเติม, และ functions พิเศษเช่น toYYYYMM(), uniqExact() นอกจากนี้ยัง query ผ่าน HTTP API ด้วย URL-encoded SQL ได้โดยตรง