结尾那段 INSERT ... SELECT 正好截断了,先补上,因为灌数据这块很多人卡的地方都在这里:
INSERT INTO bbs.page_views
SELECT
today() - number % 90 AS event_date,
now() - number * 30 AS event_time,
number % 50000 AS post_id,
number % 60 AS board_id,
toUInt8(number % 5 = 0) AS is_guest,
number % 5000 AS user_id,
rand() % 120000 AS stay_ms
FROM numbers(5000000);
numbers(N) 是 ClickHouse 自带的一张虚拟表,一行代码就能造出千万级数据,做压测非常好用。上面这一条数据量大约 500 万行、每条 3 秒左右,足够做压测。
补几个实践中的点:
1. board_id 建议用 LowCardinality(UInt16)。版块数量就几十个,字典编码后压缩率和扫描都更好;同理帖子状态、用户组这类也用得上。基数超过几万的列不要硬套 LowCardinality,反而会变慢。
2. 千万别循环单行 INSERT。这是新手最容易踩的坑:每次 INSERT 都会在磁盘上生成一个 part,攒到几百个就触发 Too many parts 报错,写入直接卡住。要么用 INSERT ... SELECT 批量灌,要么在应用侧攒够 1 万到 10 万行再批量提交一次;官方的 clickhouse-client --query "INSERT ... FORMAT JSONEachRow" 配合 stdin 也行。
3. 排序键顺序有讲究。你写的 (board_id, event_date, post_id) 是对的——把查询中最常用的等值过滤列放最前面,才能让稀疏索引起作用;如果查询常按时间范围扫描,把 event_date 往前挪。只有带上排序键前缀的条件,才能真正裁剪数据、跳过大量数据块。
4. 预聚合用物化视图,不要每次都做全表扫描。“近 7 天新增用户趋势”这类固定报表,建一张 SummingMergeTree 加物化视图,写入时自动按天聚合,查询就从秒级变成毫秒级。论坛场景尤其推荐这么做。
回到论坛这个例子:把 MySQL 的业务数据同步一份到 ClickHouse,统计完全不用实时同步——每天凌晨用计划任务跑一次增量同步就够了。Clara 本身就有计划任务体系(Cron::register 注册,前台访问懒触发,也可以配 crontab 打 /cron 入口),加个插件每天把浏览和签到流水搬过去,比在 MySQL 上硬扛统计查询划算得多。
最后一个坑:TTL 和分区别一起设得太细。按月分区配 90 天 TTL 是合理的;如果按天分区再配 90 天 TTL,就会产生 90 个活跃分区,后台合并线程的压力会明显变大。
正式会员
认证极客
见习用户






