ClickHouse命令行与SQL语法详解
-
- 一、ClickHouse命令行与SQL语法详解
-
- [第一部分:ClickHouse SQL 命令行客户端 (`clickhouse-client`)](#第一部分:ClickHouse SQL 命令行客户端 (
clickhouse-client
)) -
- [1. 基础连接](#1. 基础连接)
- [2. 核心命令行参数](#2. 核心命令行参数)
- [3. 数据导入与导出实战](#3. 数据导入与导出实战)
- [第二部分:ClickHouse SQL 语法详解](#第二部分:ClickHouse SQL 语法详解)
-
- [1. DDL (数据定义语言)](#1. DDL (数据定义语言))
- [2. DML (数据操作语言)](#2. DML (数据操作语言))
- [3. 查看元数据](#3. 查看元数据)
- 第三部分:实战示例与最佳实践
-
- [示例 1:用户行为分析](#示例 1:用户行为分析)
- [示例 2:使用 `FINAL` 优化版本合并](#示例 2:使用
FINAL
优化版本合并) - 最佳实践:
- [第一部分:ClickHouse SQL 命令行客户端 (`clickhouse-client`)](#第一部分:ClickHouse SQL 命令行客户端 (
- 二、常见高级用法
-
- [1. 物化视图 (Materialized Views) - 预聚合之王](#1. 物化视图 (Materialized Views) - 预聚合之王)
- [2. 高级聚合函数与聚合状态](#2. 高级聚合函数与聚合状态)
-
- [a. 近似计算 (Approximate Calculations)](#a. 近似计算 (Approximate Calculations))
- [b. 聚合状态管理 (`*State` / `*Merge`)](#b. 聚合状态管理 (
*State
/*Merge
))
- [3. 窗口函数 (Window Functions)](#3. 窗口函数 (Window Functions))
- [4. 高性能连接 (JOIN) 策略](#4. 高性能连接 (JOIN) 策略)
-
- [a. 使用字典 (Dictionaries) 代替小表 JOIN](#a. 使用字典 (Dictionaries) 代替小表 JOIN)
- [b. 正确的 JOIN 语法和顺序](#b. 正确的 JOIN 语法和顺序)
- [5. 嵌套数据结构与 Map 类型](#5. 嵌套数据结构与 Map 类型)
-
- [a. 使用 `Nested` 类型模拟嵌套结构](#a. 使用
Nested
类型模拟嵌套结构) - [b. 使用 `Map` 类型 (推荐)](#b. 使用
Map
类型 (推荐))
- [a. 使用 `Nested` 类型模拟嵌套结构](#a. 使用
- [6. 外部数据与表函数 (Table Functions)](#6. 外部数据与表函数 (Table Functions))
- [7. 数据生命周期管理 (TTL)](#7. 数据生命周期管理 (TTL))
- [8. 项目投影 (Projections)](#8. 项目投影 (Projections))
- 总结与最佳实践
- 三、数据类型
-
- 一、基础类型
-
- [1. 整数类型(固定长度,有符号/无符号)](#1. 整数类型(固定长度,有符号/无符号))
- [2. 浮点类型(近似计算)](#2. 浮点类型(近似计算))
- [3. 十进制类型(精确计算)](#3. 十进制类型(精确计算))
- [4. 布尔类型](#4. 布尔类型)
- 二、字符串类型
-
- [1. `String`](#1.
String
) - [2. `FixedString(N)`](#2.
FixedString(N)
)
- [1. `String`](#1.
- 三、时间日期类型
- 四、复杂与高阶类型
-
- [1. `Array(T)`](#1.
Array(T)
) - [2. `Nullable(T)`](#2.
Nullable(T)
) - [3. `Tuple(T1, T2, ...)`](#3.
Tuple(T1, T2, ...)
) - [4. `LowCardinality(T)`](#4.
LowCardinality(T)
) - [5. `Enum8`, `Enum16`](#5.
Enum8
,Enum16
)
- [1. `Array(T)`](#1.
- [五、域类型(Domain-Specific Types)](#五、域类型(Domain-Specific Types))
-
- [1. `IPv4`, `IPv6`](#1.
IPv4
,IPv6
) - [2. `UUID`](#2.
UUID
)
- [1. `IPv4`, `IPv6`](#1.
- 六、其他特殊类型
-
- [1. `Nested`](#1.
Nested
) - [2. `AggregateFunction`](#2.
AggregateFunction
)
- [1. `Nested`](#1.
- 总结与最佳实践
- 四、相关文献
一、ClickHouse命令行与SQL语法详解
第一部分:ClickHouse SQL 命令行客户端 (clickhouse-client
)
clickhouse-client
是与 ClickHouse 服务器交互的主要命令行工具。
1. 基础连接
连接本地默认实例:
bash
clickhouse-client
指定连接参数:
bash
clickhouse-client \
--host=your-clickhouse-server.com \ # 或 -h
--port=9000 \ # 或 -P
--user=default \ # 或 -u
--password \ # 安全方式,会提示输入密码
--database=my_database # 或 -d,指定初始数据库
2. 核心命令行参数
参数 | 说明 | 示例 |
---|---|---|
-q, --query |
执行单条查询后退出 | -q "SELECT 1" |
-m, --multiline |
允许多行查询(按回车不立即执行) | clickhouse-client -m |
--multiquery |
允许 -q 参数中包含多条用分号分隔的 SQL |
-q "SELECT 1; SELECT 2;" |
-f, --format |
极其重要:指定输入/输出格式 | --format=CSV |
--time |
打印查询执行时间 | --time |
-i, --input_format |
指定输入数据的格式(用于 INSERT ) |
--input_format=CSV |
--vertical |
以垂直格式输出结果(适用于宽表) | --vertical |
--param_<name> |
为参数化查询传参 | --param_id=5 (配合 {id:UInt32} ) |
3. 数据导入与导出实战
导出查询结果到 CSV 文件:
bash
clickhouse-client -q "
SELECT *
FROM sales
WHERE event_date = today()
" --format=CSVWithNames > sales_today.csv
从 CSV 文件导入数据:
bash
# 假设 data.csv 格式: 1,Alice,100.5
clickhouse-client -q "
INSERT INTO my_table
FORMAT CSV
" < data.csv
# 或者使用管道
cat data.csv | clickhouse-client -q "INSERT INTO my_table FORMAT CSV"
常用格式: JSONEachRow
, CSV
, TSV
, PrettyCompact
(默认,人类可读), Null
(不输出,用于测试性能)。
第二部分:ClickHouse SQL 语法详解
ClickHouse 的 SQL 语法与标准 SQL 高度兼容,但包含大量针对分析场景的扩展和优化。
1. DDL (数据定义语言)
a. 创建数据库
sql
CREATE DATABASE IF NOT EXISTS my_db
ENGINE = Atomic; -- 默认引擎,推荐
b. 创建表(核心)
ClickHouse 的强大功能很大程度上体现在其丰富的表引擎上。
MergeTree 系列 (最核心):
sql
CREATE TABLE my_table (
event_date Date, -- 日期
event_time DateTime, -- 时间
user_id UInt32, -- 用户ID,无符号32位整型
page_url String, -- 字符串
duration Float32, -- 浮点数
status Enum8('success' = 1, 'fail' = 2) -- 枚举
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(event_date) -- 按年月分区
ORDER BY (event_date, user_id) -- 排序键(主键)
SETTINGS index_granularity = 8192; -- 索引粒度
PARTITION BY
:分区键。通常按日期分区,加速数据管理和删除。ORDER BY
:排序键(ClickHouse 的主键概念)。这是查询性能最关键的因素,决定了数据在磁盘上的存储顺序。PRIMARY KEY
:主键(与ORDER BY
默认相同),用于一级索引。
其他常用引擎:
Log
/TinyLog
/StripeLog
:用于小表或临时数据。Memory
:内存表,重启后数据丢失。Kafka
:用于从 Kafka 主题消费数据。MySQL
/PostgreSQL
:将外部数据库的表映射到 ClickHouse。MaterializedView
:物化视图,自动转换和聚合数据。Distributed
:分布式表引擎,不存储数据,而是将查询路由到集群中的分片上。
c. 修改表
sql
-- 添加列
ALTER TABLE my_table ADD COLUMN browser String AFTER user_id;
-- 修改列类型
ALTER TABLE my_table MODIFY COLUMN duration UInt32;
-- 删除列
ALTER TABLE my_table DROP COLUMN browser;
2. DML (数据操作语言)
a. 插入数据 (INSERT
)
sql
-- 标准插入
INSERT INTO my_table VALUES (..., ...);
-- 指定列插入
INSERT INTO my_table (event_date, user_id) VALUES ('2023-10-01', 12345);
-- 从查询结果插入
INSERT INTO target_table
SELECT ... FROM source_table WHERE ...;
b. 查询数据 (SELECT
) - 核心中的核心
ClickHouse 的 SELECT
支持所有标准语法,并有许多强大扩展。
嵌套子查询和 CTE:
sql
WITH active_users AS (
SELECT DISTINCT user_id
FROM events
WHERE event_date >= today() - 7
)
SELECT
u.user_id,
count() AS event_count
FROM active_users AS u
JOIN events AS e ON u.user_id = e.user_id
GROUP BY u.user_id
HAVING event_count > 10;
数组操作 (特色功能):
sql
SELECT
user_id,
-- 创建数组
['pageview', 'login', 'purchase'] AS actions,
-- 数组函数:计算长度
length(actions) AS action_count,
-- 数组函数:判断是否存在
has(actions, 'login') AS has_login,
-- 数组函数:聚合组内数据成数组
groupArray(page_url) AS visited_pages
FROM events
GROUP BY user_id;
高级函数:
sql
SELECT
-- 条件函数
if(duration > 10, 'Long', 'Short') AS session_type,
-- 多条件分支
multiIf(status = 200, 'OK', status = 404, 'Not Found', 'Error') AS status_desc,
-- 聚合函数:近似去重(极快)
uniqHLL12(user_id) AS approx_unique_users,
-- 聚合函数:分位数
quantile(0.99)(duration) AS p99_duration
FROM events
GROUP BY session_type, status_desc;
c. 删除数据 (ALTER TABLE ... DELETE
)
注意 :ClickHouse 的 DELETE
是异步的、后台执行的 ALTER
操作。
sql
ALTER TABLE my_table DELETE WHERE event_date < '2023-01-01';
3. 查看元数据
sql
-- 查看所有数据库
SHOW DATABASES;
-- 查看表结构
DESCRIBE TABLE my_table;
-- 查看建表语句
SHOW CREATE TABLE my_table;
-- 查看表大小和行数
SELECT
name,
formatReadableSize(total_bytes) AS size,
total_rows
FROM system.parts
WHERE table = 'my_table' AND active;
第三部分:实战示例与最佳实践
示例 1:用户行为分析
sql
-- 计算每小时的PV和UV,以及平均会话时长
SELECT
toStartOfHour(event_time) AS hour,
count() AS pv, -- 页面浏览量
uniq(user_id) AS uv, -- 独立用户数
avg(duration) AS avg_duration
FROM events
WHERE event_date = today()
GROUP BY hour
ORDER BY hour;
示例 2:使用 FINAL
优化版本合并
对于 CollapsingMergeTree
或 ReplacingMergeTree
引擎,查询时使用 FINAL
可以强制合并版本,但可能很慢。
sql
SELECT *
FROM my_replacing_table
FINAL
WHERE user_id = 123;
最佳实践:
- 避免
SELECT *
:始终指定需要的列。列式存储下,读取不需要的列代价高昂。 - 优先使用分区键和排序键 :在
WHERE
和ORDER BY
子句中优先使用这些列,以利用索引。 - 使用近似计算 :如
uniqHLL12()
代替uniqExact()
,用quantile()
代替精确分位数,以极大提升性能。 - 预聚合 :使用
SummingMergeTree
或AggregatingMergeTree
引擎和物化视图,在数据写入时进行预聚合。 - 谨慎使用
JOIN
:ClickHouse 的JOIN
性能不如传统 OLTP 数据库。通常建议反规范化(宽表)或预先过滤右表。 - 关注数据类型 :使用最紧凑、最合适的数据类型(如
UInt32
而非UInt64
)。
通过熟练掌握 clickhouse-client
工具和 ClickHouse 特有的 SQL 语法,你可以极大地提升大数据分析的效率和性能。
二、常见高级用法
下文将深入探讨 ClickHouse 数据分析的高级用法,包括物化视图、高级聚合、近似计算、分布式查询优化等核心特性。
1. 物化视图 (Materialized Views) - 预聚合之王
物化视图是 ClickHouse 中最强大的功能之一。它不是一个简单的视图,而是一个在底层隐式创建并持续更新的特殊表 。当源表 (INSERT
) 写入新数据时,物化视图会自动、增量地将这些数据按照预定义的聚合逻辑进行计算和存储。
场景:实时计算每分钟的页面浏览量(PV)和独立用户数(UV)。
基础表 (存储原始数据):
sql
CREATE TABLE events_raw (
event_time DateTime,
user_id UInt32,
page_url String,
event_type String
) ENGINE = MergeTree()
ORDER BY (event_time, user_id);
物化视图 (存储预聚合结果):
sql
CREATE MATERIALIZED VIEW events_agg_minute
ENGINE = SummingMergeTree() -- 指定物化视图自身的存储引擎
PARTITION BY toYYYYMM(event_minute)
ORDER BY (event_minute, page_url)
AS SELECT
toStartOfMinute(event_time) AS event_minute,
page_url,
count() AS pv, -- 求和合并
uniqState(user_id) AS uv_state -- 存储UV的中间状态(AggregateFunction类型)
FROM events_raw
GROUP BY event_minute, page_url;
查询物化视图:
sql
SELECT
event_minute,
page_url,
sum(pv) AS pv, -- 对pv直接求和
uniqMerge(uv_state) AS uv -- 对UV状态进行合并计算
FROM events_agg_minute
GROUP BY event_minute, page_url;
优势:
- 查询极快:直接查询预先计算好的聚合结果,而非扫描原始数据。
- 开销极低:在数据插入时增量计算,分散了计算压力。
2. 高级聚合函数与聚合状态
ClickHouse 提供了丰富的聚合函数,特别是对于中间状态 (*State
) 和合并结果 (*Merge
) 的操作,这是实现预聚合的基础。
a. 近似计算 (Approximate Calculations)
以精度换取速度,非常适合海量数据下的快速分析。
-
基数估计:
sql-- 精确去重 (慢) SELECT uniqExact(user_id) FROM events; -- 近似去重 (极快,误差~1.5%) SELECT uniq(user_id) FROM events; SELECT uniqHLL12(user_id) FROM events; -- 更老的算法
-
分位数估计:
sql-- 计算响应时间的中位数、90分位、99分位 SELECT quantile(0.5)(response_time_ms) AS p50, quantile(0.9)(response_time_ms) AS p90, quantile(0.99)(response_time_ms) AS p99 FROM requests;
b. 聚合状态管理 (*State
/ *Merge
)
这是实现物化视图和高级聚合的基石。
sql
-- 1. 查询时直接使用状态函数,返回二进制状态,不是最终值。
SELECT quantileState(0.5)(response_time_ms) AS p50_state FROM requests;
-- 2. 将状态存入表或物化视图(如上文的uv_state)。
-- 3. 在更高层的聚合中,合并这些状态得到最终结果。
SELECT quantileMerge(0.5)(p50_state) AS final_p50 FROM agg_table;
3. 窗口函数 (Window Functions)
ClickHouse 支持标准的 SQL 窗口函数,用于复杂的数据分析。
场景:计算每个用户最近3次访问的页面时长移动平均。
sql
SELECT
user_id,
event_time,
page_url,
duration_ms,
avg(duration_ms) OVER (
PARTITION BY user_id
ORDER BY event_time ASC
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW -- 最近3行(当前行 + 前2行)
) AS moving_avg_duration
FROM events
ORDER BY user_id, event_time;
常用窗口函数 :row_number()
, rank()
, lag()
, lead()
, sum() OVER (...)
, avg() OVER (...)
。
4. 高性能连接 (JOIN) 策略
在 OLAP 数据库中,JOIN
是昂贵的操作。ClickHouse 提供了多种策略来优化。
a. 使用字典 (Dictionaries) 代替小表 JOIN
将小维度表预加载到内存中。
sql
-- 1. 创建字典
CREATE DICTIONARY products_dict (
id UInt64,
name String,
price Decimal(10, 2)
) PRIMARY KEY id
SOURCE(CLICKHOUSE(TABLE 'products' DB 'default'))
LIFETIME(MIN 300 MAX 360)
LAYOUT(HASHED());
-- 2. 使用dictGet函数代替JOIN
SELECT
order_id,
dictGet('default.products_dict', 'name', product_id) AS product_name,
dictGet('default.products_dict', 'price', product_id) AS product_price,
quantity * product_price AS total_amount
FROM orders;
b. 正确的 JOIN 语法和顺序
-
将小表放在右侧:ClickHouse 总是将右表加载到内存中。
-
使用
GLOBAL JOIN
:在分布式查询中,确保右表被发送到所有节点。sqlSELECT ... FROM distributed_left_table AS l GLOBAL INNER JOIN local_small_right_table AS r ON l.id = r.id;
5. 嵌套数据结构与 Map 类型
处理半结构化数据,如 JSON 中的数组或键值对。
a. 使用 Nested
类型模拟嵌套结构
sql
CREATE TABLE events (
timestamp DateTime,
user_id UInt32,
`tags.keys` Array(String),
`tags.values` Array(String)
) ENGINE = MergeTree()
ORDER BY (user_id, timestamp);
-- 查询:查找包含标签 "env":"prod" 的事件
SELECT *
FROM events
WHERE has((tags.keys, tags.values), ('env', 'prod'));
b. 使用 Map
类型 (推荐)
sql
CREATE TABLE events (
timestamp DateTime,
user_id UInt32,
tags Map(String, String)
) ENGINE = MergeTree()
ORDER BY (user_id, timestamp);
-- 查询更加直观
SELECT *
FROM events
WHERE tags['env'] = 'prod';
6. 外部数据与表函数 (Table Functions)
无需建表,直接查询外部数据源。
-
查询 CSV 文件:
sqlSELECT * FROM file('data.csv', CSVWithNames, 'column1 String, column2 UInt32') WHERE column2 > 100;
-
查询 URL:
sqlSELECT * FROM url('https://example.com/data.json', JSONEachRow, 'id UInt32, data String');
-
查询 MySQL 表:
sqlSELECT * FROM mysql('mysql-host:3306', 'database', 'table', 'user', 'password');
7. 数据生命周期管理 (TTL)
自动处理旧数据,是实现数据分区和保留策略的核心。
-
行级 TTL:自动删除或移动过期数据。
sqlCREATE TABLE logs ( event_time DateTime, message String ) ENGINE = MergeTree() ORDER BY event_time TTL event_time + INTERVAL 30 DAY; -- 30天后自动删除数据 -- 或者将数据移动到廉价存储 TTL event_time + INTERVAL 7 DAY TO DISK 'hdd2', event_time + INTERVAL 30 DAY TO VOLUME 'archive';
-
列级 TTL:自动将某列重置为默认值。
sqlCREATE TABLE sessions ( created DateTime, session_data String TTL created + INTERVAL 1 HOUR ) ENGINE = MergeTree() ORDER BY created;
8. 项目投影 (Projections)
物化视图的现代替代品,与主表数据一起存储,由查询优化器自动选择使用,无需应用层干预。管理更简单,性能更高。
场景:为不同的排序键创建投影以加速不同维度的查询。
sql
CREATE TABLE sales (
event_date Date,
product_id UInt32,
customer_id UInt32,
amount Decimal(10, 2)
) ENGINE = MergeTree()
ORDER BY (event_date, product_id); -- 主排序键
-- 创建一个按客户ID聚合的投影
ALTER TABLE sales
ADD PROJECTION sales_by_customer (
SELECT
event_date,
customer_id,
sum(amount)
GROUP BY event_date, customer_id
);
-- 插入数据后,投影会自动构建
INSERT INTO sales ...;
-- 查询时,ClickHouse 优化器会自动判断是否使用投影
SELECT event_date, customer_id, sum(amount)
FROM sales
GROUP BY event_date, customer_id; -- 此查询会命中投影,极快!
总结与最佳实践
高级用法 | 核心思想 | 适用场景 |
---|---|---|
物化视图 (Materialized Views) | 空间换时间,预聚合 | 实时报表、指标看板 |
近似计算 (uniq, quantile) | 精度换速度 | 海量数据下的快速趋势分析 |
聚合状态 (State/Merge) | 分布式聚合 | 构建分层聚合系统 |
字典 (Dictionaries) | 内存换时间,避免JOIN | 关联小维度表 |
窗口函数 (Window Functions) | 行间计算 | 用户行为分析、时间序列分析 |
Map类型 / 投影 | 处理半结构化数据 | 处理JSON、标签等灵活字段 |
TTL | 自动化数据管理 | 日志、事件等有时效性的数据 |
表函数 (file, url, mysql) | 联邦查询 | 数据探查、临时分析、数据集成 |
项目投影 (Projections) | 自动查询优化 | 为不同维度的查询加速 |
终极建议:
- 优先考虑预聚合:90% 的性能问题可以通过物化视图和投影解决。
- 敢于使用近似计算:在可接受的误差范围内,换取数量级的性能提升。
- 避免大表 JOIN:使用字典、反规范化(宽表)或应用程序层处理。
- 拥抱 TTL:让数据管理自动化,避免手动清理的麻烦和风险。
- 尝试投影:在新的设计中,优先使用投影而不是物化视图来加速查询。
掌握这些高级用法,你就能充分利用 ClickHouse 的潜力,构建出高效、稳定且易于维护的海量数据分析平台。
三、数据类型
一、基础类型
1. 整数类型(固定长度,有符号/无符号)
设计哲学:提供多种长度的整数,让你可以精确选择所需位数,避免浪费空间。
类型 | 取值范围(有符号) | 取值范围(无符号) | 存储字节 | 示例 |
---|---|---|---|---|
Int8 |
-128 到 127 | - | 1 | Int8(5) |
Int16 |
-32768 到 32767 | - | 2 | Int16(1000) |
Int32 |
-2^31 到 2^31-1 | - | 4 | Int32(42500) |
Int64 |
-2^63 到 2^63-1 | - | 8 | Int64(34200000000) |
UInt8 |
- | 0 到 255 | 1 | UInt8(255) (状态码) |
UInt16 |
- | 0 到 65535 | 2 | UInt16(60000) |
UInt32 |
- | 0 到 2^32-1 | 4 | UInt32(4000000000) |
UInt64 |
- | 0 到 2^64-1 | 8 | UInt64(100000000000) |
最佳实践 :永远使用能满足你数据范围的最小类型 。例如,存储年龄用 UInt8
,存储页面访问量用 UInt32
。
2. 浮点类型(近似计算)
设计哲学:牺牲微小精度以换取极高的计算速度,适合大规模数值计算。
类型 | 精度 | 存储字节 | 备注 |
---|---|---|---|
Float32 |
约 7 位有效数字 | 4 | 单精度,对应 float |
Float64 |
约 16 位有效数字 | 8 | 双精度,对应 double |
注意 :由于浮点数的精度问题,对它们进行相等比较 (=
) 可能是不可靠的。适用于指标计算、科学计算,不适用于金融金额。
3. 十进制类型(精确计算)
设计哲学:提供精确的定点数运算,适合金融、货币等需要精确计算的场景。
类型 | 语法 | 说明 | 示例 |
---|---|---|---|
Decimal32 |
Decimal32(S) |
精度最高为 9 位数字,S 为小数位数 |
Decimal32(4) -> 总共9位,小数占4位 |
Decimal64 |
Decimal64(S) |
精度最高为 18 位数字 | Decimal64(8) |
Decimal128 |
Decimal128(S) |
精度最高为 38 位数字 | Decimal128(16) |
Decimal256 |
Decimal256(S) |
精度最高为 76 位数字 | Decimal256(30) |
最佳实践 :根据所需的整数位数和小数位数来选择。例如,存储全球GDP可能需要 Decimal128(2)
。
4. 布尔类型
ClickHouse 没有单独的 Boolean
类型。它使用 UInt8
类型,用 0
和 1
来表示 false
和 true
。
二、字符串类型
1. String
- 说明:可以存储任意长度的文本,长度无限制。编码为 UTF-8。
- 适用场景 :默认的字符串类型。存储URL、日志、JSON字符串、变长文本等。
- 示例 :
'Hello, 世界!'
,'https://example.com'
2. FixedString(N)
- 说明 :固定长度
N
的字符串。如果插入的字符串长度小于N
,则会用空字节 (\0
) 填充;如果更长,则会抛出异常。 - 适用场景 :存储长度几乎固定的标识符,如 MD5哈希值(32) 、国家代码(2) 、IP地址(15) 等。查询性能比
String
更高。 - 示例 :
FixedString(32)
用于存储'4d7e6e7b0d6e7a7b6e7d6e7a6e7d6e7a'
三、时间日期类型
设计哲学:提供细粒度的时间类型,内部存储为整数,计算效率极高。
类型 | 分辨率 | 格式 | 示例 |
---|---|---|---|
Date |
天 | YYYY-MM-DD |
'2023-10-27' |
DateTime |
秒 | YYYY-MM-DD HH:MM:SS |
'2023-10-27 14:30:00' |
DateTime64 |
亚秒 | YYYY-MM-DD HH:MM:SS.NNNNNNNNN |
DateTime64(3) -> 毫秒 '2023-10-27 14:30:00.123' |
关键点:
- 可以指定时区:
DateTime('Asia/Shanghai')
。 DateTime64
可以指定小数秒的精度,如DateTime64(6)
为微秒。- 最佳实践 :始终使用最细粒度的时间类型,因为你总是可以从高精度转换到低精度(如按天聚合),但反之则不行。
四、复杂与高阶类型
这些类型是 ClickHouse 强大功能的体现。
1. Array(T)
-
说明 :由
T
类型元素组成的数组,T
可以是任意类型,甚至另一个Array
。 -
操作 :支持丰富的数组函数 (
arrayMap
,arrayFilter
,arrayCount
) 和 Lambda 表达式。 -
示例 :
sql-- 创建数组 SELECT [1, 2, 3] AS numbers; -- 数组函数 SELECT arrayFilter(x -> x > 1, [1, 2, 3, 4]) AS filtered; -- [2,3,4]
2. Nullable(T)
- 说明 :允许
T
类型的值为NULL
。 - 注意 :谨慎使用!
Nullable
类型会使列的处理速度变慢并增加存储开销,因为需要额外的一个字节来存储NULL
标记。如果业务上不可能为NULL
,就不要用。 - 示例 :
Nullable(String)
表示一个可能为NULL
的字符串。
3. Tuple(T1, T2, ...)
- 说明:元组,用于存储一组有序的、类型可能不同的值。
- 适用场景:临时组合多个值,常用于函数返回多个结果或存储少量关联数据。
- 示例 :
Tuple(String, UInt8, Float32)
->('Alice', 25, 99.5)
4. LowCardinality(T)
- 说明 :极其重要的高性能类型 。用于包装基数低( distinct 值数量少)的
String
、FixedString
、Date
、DateTime
类型以及整数类型。 - 原理:内部使用字典编码,将原始值映射为更小的整数,极大减少存储空间并加速查询。
- 适用场景 :状态码、性别、国家、枚举值、标签等。
- 示例 :
LowCardinality(String)
存储'success'
,'fail'
,'pending'
。
5. Enum8
, Enum16
-
说明 :枚举,将字符串映射到数字值进行存储,是
LowCardinality
的一种特化和提前定义。 -
适用场景:固定的、预定义的字符串集合。
-
示例 :
sqlCREATE TABLE logs ( level Enum8('ERROR' = 1, 'WARNING' = 2, 'INFO' = 3) ); INSERT INTO logs VALUES ('ERROR');
五、域类型(Domain-Specific Types)
这些类型是语法糖,底层用其他类型存储,但提供了更清晰的语义和专用的函数。
1. IPv4
, IPv6
-
底层存储 :
IPv4
存为UInt32
,IPv6
存为FixedString(16)
。 -
优点 :提供专用的函数(如
IPv4NumToString
,toIPv4
)和格式检查。 -
示例 :
sqlSELECT toIPv4('192.168.0.1') AS ip WHERE ip > toIPv4('192.168.0.0');
2. UUID
- 说明 :通用唯一标识符,存储为
FixedString(16)
。 - 示例 :
UUID('12345678-1234-1234-1234-123456789abc')
六、其他特殊类型
1. Nested
-
说明 :用于创建嵌套数据结构,它本质上是将多个
Array
列组合在一起,保证其数组长度相同。 -
适用场景:处理半结构化数据,如来自 JSON 的事件列表。
-
示例 :
sqlCREATE TABLE events ( timestamp DateTime, user_id UInt32, `actions.names` Array(String), `actions.values` Array(Int32) ) ENGINE = MergeTree() ORDER BY (user_id, timestamp);
(注意:这实际上是模拟嵌套,并非真正的嵌套类型,但概念一致)。
2. AggregateFunction
-
说明 :非常特殊且强大 。它不存储数据本身,而是存储数据的中间聚合状态 (如
uniqState
,quantileState
)。 -
适用场景 :与物化视图 结合使用,实现预聚合,是 ClickHouse 应对超大数据量的王牌功能。
-
示例 :
sql-- 创建一个存储聚合状态的物化视图 CREATE MATERIALIZED VIEW mv_agg ENGINE = AggregatingMergeTree() ORDER BY (date, product_id) AS SELECT date, product_id, sumState(amount) AS total_amount, -- 存储的是聚合状态,不是最终值 uniqState(user_id) AS unique_users FROM sales_raw GROUP BY date, product_id; -- 查询时,使用相应的合并函数获取最终结果 SELECT date, product_id, sumMerge(total_amount) AS total_sales, -- 合并状态得到最终结果 uniqMerge(unique_users) AS total_customers FROM mv_agg GROUP BY date, product_id;
总结与最佳实践
- 精确选择类型 :使用能满足需求的最小、最精确的类型(如
UInt8
而非UInt64
)。 - 字符串优化 :对基数低的字符串列,毫不犹豫地使用
LowCardinality(String)
。对固定长度的标识符,使用FixedString(N)
。 - 避免滥用 Nullable :除非必要,否则不要使用
Nullable
,因为它有性能开销。 - 时间类型 :始终使用最细粒度的时间类型(如
DateTime64
)。 - 金融计算 :使用
Decimal
系列类型,避免使用Float
。 - 探索复杂类型 :善用
Array
、Tuple
和Map
来处理复杂数据结构。 - 王牌功能 :在需要极致性能的聚合场景,学习和使用
AggregateFunction
与物化视图。
通过合理选择数据类型,你可以极大地提升 ClickHouse 的存储效率和查询性能。