ClickHouse 从零到精通的实战指南

张开发
2026/4/6 5:00:53 15 分钟阅读

分享文章

ClickHouse 从零到精通的实战指南
1. ClickHouse 入门指南从安装到第一个查询第一次接触ClickHouse时我被它处理十亿级数据的速度震惊了。记得当时用传统数据库需要跑半小时的聚合查询在ClickHouse上3秒就出了结果。这种性能优势让它成为我们团队分析日志和用户行为的首选工具。ClickHouse本质上是一个列式存储的OLAP数据库特别适合处理海量数据的分析查询。和MySQL这类行式数据库不同它的数据是按列存储的这样在做聚合计算时只需要读取相关列避免了全表扫描。我常跟团队新人解释想象你要统计全校学生的平均年龄 - 行式存储需要查看每个学生的完整档案而列式存储直接去年龄那摞文件里计算就行。安装ClickHouse比想象中简单得多。在Ubuntu 20.04上只需要四条命令sudo apt-get install -y apt-transport-https ca-certificates dirmngr sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv E0C56BD4 echo deb https://repo.clickhouse.com/deb/stable/ main/ | sudo tee \ /etc/apt/sources.list.d/clickhouse.list sudo apt-get update sudo apt-get install -y clickhouse-server clickhouse-client安装完成后启动服务并连接客户端sudo service clickhouse-server start clickhouse-client第一次建表时我犯了个典型错误 - 直接照搬MySQL的表结构。后来才发现ClickHouse的MergeTree引擎需要精心设计分区键和排序键。比如处理日志数据时好的建表语句应该是这样CREATE TABLE logs ( timestamp DateTime, user_id UInt32, event_type String, device String ) ENGINE MergeTree() PARTITION BY toYYYYMMDD(timestamp) ORDER BY (event_type, user_id) SETTINGS index_granularity 8192;这里PARTITION BY按天分区ORDER BY确定了数据在磁盘上的物理顺序。有次我们查询特定事件类型的用户行为因为event_type在排序键首位查询速度比随机排序快了20倍。2. 核心功能深度解析MergeTree引擎的实战技巧MergeTree是ClickHouse的明星引擎我们团队90%的表都用它。但要用好它需要理解几个关键概念。首先是分区策略 - 我们曾因分区不当吃过亏。有次按月份分区查询还是很慢后来改成按天分区查询速度直接提升了一个数量级。数据导入也有讲究。小批量频繁插入会导致大量小分区严重影响性能。我们现在的做法是-- 批量插入10万条数据 INSERT INTO logs VALUES (2023-06-01 12:00:00, 1001, login, iOS), (2023-06-01 12:01:00, 1002, purchase, Android), ... -- 更多数据对于超大规模数据我们使用clickhouse-client的批量模式cat data.csv | clickhouse-client --queryINSERT INTO logs FORMAT CSV查询优化方面有几点实战经验值得分享避免SELECT *只查询需要的列优先使用分区键和排序键作为过滤条件对于大范围查询加上SAMPLE子句快速获取近似结果比如分析用户行为路径时高效查询是这样的SELECT user_id, sequenceMatch((?1).*(?2))(timestamp, event_type view, event_type purchase) AS funnel FROM logs WHERE timestamp BETWEEN 2023-06-01 AND 2023-06-07 GROUP BY user_id3. 高级特性实战物化视图与分布式查询物化视图是ClickHouse的一大杀器。我们用它预计算常用指标查询速度提升百倍不止。比如实时统计DAUCREATE MATERIALIZED VIEW dau_mv ENGINE AggregatingMergeTree() PARTITION BY toYYYYMM(date) ORDER BY date AS SELECT toDate(timestamp) AS date, uniqState(user_id) AS users FROM logs GROUP BY date;查询时使用uniqMergeSELECT date, uniqMerge(users) AS dau FROM dau_mv WHERE date BETWEEN 2023-06-01 AND 2023-06-30 GROUP BY date;分布式集群配置是另一个重点。我们的生产环境采用3分片2副本架构配置文件config.xml关键部分如下remote_servers cluster shard replica hostnode1/host port9000/port /replica replica hostnode2/host port9000/port /replica /shard shard replica hostnode3/host port9000/port /replica replica hostnode4/host port9000/port /replica /shard /cluster /remote_servers跨集群查询时使用GLOBAL IN代替普通IN能显著提升性能。有次优化前查询耗时45秒改用GLOBAL IN后降到3秒。4. Spring Boot集成实战从配置到性能优化在Spring Boot项目中集成ClickHouse我们走过了不少弯路。最开始用原生JDBC后来切换到MyBatis动态数据源。推荐配置如下spring: datasource: dynamic: primary: clickhouse datasource: clickhouse: driver-class-name: ru.yandex.clickhouse.ClickHouseDriver url: jdbc:clickhouse://localhost:8123/default username: default password: DAO层使用DS注解切换数据源Repository DS(clickhouse) public interface UserBehaviorMapper { Select(SELECT event_type, count() FROM logs WHERE user_id #{userId} GROUP BY event_type) ListMapString, Object getUserEvents(Param(userId) long userId); }性能优化方面我们总结了几个关键点连接池配置最大连接数不要超过ClickHouse的max_concurrent_queries批量插入使用PreparedStatement每批5万-10万条查询设置合适的fetch_size避免内存溢出对于复杂查询我们直接在ClickHouse中创建物化视图Spring Boot只查询预计算结果。比如用户分群分析public ListUserSegment analyzeUserSegments(LocalDate from, LocalDate to) { String sql SELECT segment, count() FROM user_segments_mv WHERE date BETWEEN ? AND ? GROUP BY segment; return jdbcTemplate.query(sql, ps - { ps.setString(1, from.toString()); ps.setString(2, to.toString()); }, (rs, rowNum) - new UserSegment( rs.getString(segment), rs.getLong(count) )); }5. 生产环境踩坑指南在线上环境运行ClickHouse三年我们积累了不少血泪教训。最严重的一次事故是ZooKeeper集群故障导致所有分布式表不可用。现在我们的容灾方案是关键表同时创建本地和分布式版本定期备份元数据监控ZooKeeper健康状态内存管理也很关键。有次复杂查询导致OOM后来我们调整了这些参数max_memory_usage10000000000/max_memory_usage !-- 10GB -- max_bytes_before_external_sort5000000000/max_bytes_before_external_sort max_bytes_before_external_group_by5000000000/max_bytes_before_external_group_by查询监控方面system.query_log表是宝藏。我们定期分析慢查询SELECT query, elapsed, memory_usage FROM system.query_log WHERE event_date today() AND type QueryFinish ORDER BY elapsed DESC LIMIT 10数据备份我们采用双重策略使用ALTER TABLE ... FREEZE创建本地快照通过clickhouse-copier工具跨集群复制最后给新手的建议一定要先在小数据量上验证表设计我们曾因分区键选择不当在数据量增长到1TB后不得不重建整个表。

更多文章