ClickHouse学习笔记(二):Docker部署与SQL入门实战
ClickHouse学习笔记(二):Docker部署与SQL入门实战
上一篇把 ClickHouse 理解成了“负责分析大量明细数据的数据库”。这一篇直接动手:启动服务,建一张支付事实表,再回答城市销售额、支付人数和累计金额几个问题。
这次实验的目标是:每条 SQL 都知道自己在统计什么,并且能用原始记录核对结果。
系列导航:
一、环境准备与启动
| 项目 | 本文约定 |
|---|---|
| Docker | 能运行 Linux 容器;Windows 使用已启动的 Docker Desktop |
| 镜像 | clickhouse/clickhouse-server:25.8.1.5101 |
| 容器名称 | clickhouse-learning |
| 数据库 | clickhouse_learning |
| 学习用户 | learner |
| HTTP / Native 端口 | 8123 / 9000 |
| 业务时间 | Asia/Shanghai |
Docker 命令使用单行形式,在 PowerShell 和 Bash 中都不需要续行符。
先检查服务端是否已启动:
1 | docker version |
需要看到 Server 信息。如果提示无法连接 Docker daemon,先启动 Docker Desktop 并确认使用 Linux 容器。
1.1 启动容器
1 | docker run -d --name clickhouse-learning --ulimit nofile=262144:262144 -p 127.0.0.1:8123:8123 -p 127.0.0.1:9000:9000 -e CLICKHOUSE_DB=clickhouse_learning -e CLICKHOUSE_USER=learner -e CLICKHOUSE_PASSWORD=LearningOnly_123 -e CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1 -v clickhouse-learning-data:/var/lib/clickhouse clickhouse/clickhouse-server:25.8.1.5101 |
这条命令做了几件事:
- 端口映射到本机的
127.0.0.1。 - 用环境变量初始化学习用户和数据库。
- 用命名卷保存数据库数据。
- 提高文件描述符上限。
用户初始化和卷挂载方式见官方 Docker 指南。这里的密码是公开的本地实验值,命令也会留在终端历史中;正式部署需要另外管理凭据和权限。
如果端口已被占用,可以只修改宿主机一侧,比如 127.0.0.1:18123:8123。后续从宿主机访问时也要用 18123,容器内的端口仍是 8123。
1.2 确认服务可用
1 | docker logs --tail 80 clickhouse-learning |
容器显示 Up 只是进程仍在运行,以客户端能够完成查询为准。timezone() 返回的是当前会话使用的时区,不必预设它一定是上海;下面会显式设置。
进入交互客户端:
1 | docker exec -it clickhouse-learning clickhouse-client --user learner --password LearningOnly_123 --database clickhouse_learning --multiquery |
后续 SQL 在这个客户端中执行。 只有标为 Bash 的 Docker 命令在宿主机终端执行。
1 | SET session_timezone = 'Asia/Shanghai'; |
session_timezone 只影响当前会话,新连接要重新设置。本系列的时间列还会显式带上时区,减少解析和展示歧义,见官方日期时间类型。
二、建表:先明确字段和统计口径
本文的数据是支付成功事实:一个订单只写一条成功支付记录,不包含退款。
1 | CREATE TABLE clickhouse_learning.order_payments |
这里故意不用 IF NOT EXISTS:如果同名实验表已经存在,先查看 SHOW CREATE TABLE 和数据,避免以为自己创建了新表,却继续向旧表重复插入。
2.1 为什么这样选类型?
| 字段 | 类型 | 原因 |
|---|---|---|
| 订单、用户 ID | UInt64 |
示例 ID 非负,使用整数表示 |
| 城市、渠道 | LowCardinality(String) |
不同值较少,适合考虑字典编码 |
| 金额 | Decimal(12, 2) |
示例需要保留两位小数 |
| 支付时间 | DateTime('Asia/Shanghai') |
以秒为精度,明确业务时区 |
Decimal(12, 2) 中 12 是总位数,2 是小数位数。金额也可以按“分”保存为整数;Float64 的二进制浮点表示不适合随意承担需要精确到分的核算。Decimal 文档介绍了精度与运算规则。
LowCardinality 不是“所有字符串都必须使用”的模板,用户 ID、随机文本等高基数字段需要结合真实分布评估,见官方类型说明。
2.2 三个建表子句先记住含义
1 | ENGINE → 使用什么表引擎 |
下一篇专门讲它们的关系。这里先记住:ORDER BY 不提供订单 ID 唯一约束,查询输出也不因此自动按这个顺序返回。
三、插入八条固定记录
以下语句在新建的空表中执行一次:
1 | INSERT INTO clickhouse_learning.order_payments |
按这八条输入手工计算,应该得到 8 行、1000.00 元。下面的结果表同样是依据固定数据计算的预期值,不是性能测试输出。
普通 MergeTree 不会按 order_id 自动去重。重复执行 INSERT 会重复记账;本实验的查询结果依赖“初始为空、只插入一次”这个前提。
四、用 SQL 回答三个分析问题
4.1 各城市支付金额是多少?
1 | SELECT |
| 城市 | 支付笔数 | 支付金额 | 去重支付人数 |
|---|---|---|---|
| 上海 | 4 | 570.00 | 3 |
| 广州 | 2 | 250.00 | 1 |
| 北京 | 2 | 180.00 | 1 |
上海的用户 101 支付了两次,所以四笔支付对应三个人。uniqExact 做精确去重,状态大小会随不同用户数量增长;它与近似去重函数的取舍见官方函数说明。
4.2 每天 App 渠道卖了多少?
1 | SELECT |
| 日期 | 全部支付金额 | App 支付金额 | App 支付笔数 |
|---|---|---|---|
| 2026-10-01 | 450.00 | 370.00 | 3 |
| 2026-10-02 | 550.00 | 200.00 | 2 |
sumIf、countIf 是聚合函数与 -If 组合器的用法,只将满足条件的行计入对应指标,见官方组合器说明。
这里不能先写 WHERE channel = 'app',否则 total_amount 也只剩下 App 的金额。条件放在 WHERE 还是某个聚合函数里,会改变统计范围。
4.3 截至每天的累计金额是多少?
1 | SELECT |
| 日期 | 当天金额 | 累计金额 |
|---|---|---|
| 2026-10-01 | 450.00 | 450.00 |
| 2026-10-02 | 550.00 | 1000.00 |
先把明细汇总为每天一行,再用窗口函数累计。窗口的 ORDER BY 决定计算顺序,外层的 ORDER BY 决定展示顺序,见窗口函数文档。
如果某一天没有支付,查询不会自动补出那一天,需要额外补齐日期。累计金额的时间范围也只覆盖子查询实际选入的数据。
五、时间筛选与 HTTP 访问
5.1 用左闭右开的区间
查询 10 月 1 日的上海支付:
1 | SELECT order_id, amount, paid_at |
预期返回 1001 和 1003。相比拼接 23:59:59,[当天零点, 次日零点) 更容易在以后改用毫秒时间时保持边界正确。
5.2 区分 HTTP 与 Native 协议
1 | 宿主机上的 HTTP 客户端 → 127.0.0.1:8123 → ClickHouse HTTP 接口 |
宿主机终端可以执行:
1 | curl.exe --user learner:LearningOnly_123 --data-binary "SELECT count() FROM clickhouse_learning.order_payments FORMAT JSON" http://127.0.0.1:8123/ |
Windows 使用 curl.exe,避免某些 PowerShell 环境中的 curl 别名;Linux 或 macOS 改成 curl。返回 JSON 的查询方式见官方 HTTP 接口。
以后接入 Java 或其他客户端时,先核对驱动使用的协议和端口。如果应用运行在另一个容器中,应用里的 localhost 指向它自己,需要使用可达的容器服务名。
六、重复实验与排障
| 现象 | 优先检查 |
|---|---|
| 无法连接 Docker | Docker Desktop 是否启动、是否为 Linux 容器 |
| 容器创建失败 | 名称或宿主机端口是否已被占用 |
| 用户认证失败 | 用户名、密码和容器初始化配置是否一致 |
| 金额变成预期的两倍 | 是否重复插入了八条记录 |
| 同名表已存在 | 查看旧表结构,使用另一个实验表名或数据库 |
| 时间展示不符合预期 | 列时区、会话时区和输入字符串是否一致 |
查看表结构和数据:
1 | SHOW CREATE TABLE clickhouse_learning.order_payments; |
结束交互客户端输入 exit。需要暂停实验时,在宿主机执行:
1 | docker stop clickhouse-learning |
下次执行 docker start clickhouse-learning,再连接客户端即可。命名卷和实验数据仍然保留;单纯重启容器不会让表恢复为空。
完成这篇之后,应该已经能建表、导入数据并解释指标。下一篇继续拆解:PARTITION BY、ORDER BY 和主键索引到底各自负责什么?



