ClickHouse 查询
从实际使用场景出发,介绍夜莺 ClickHouse 数据源告警:用 SQL 查询做告警判定,以及值字段、标签字段与分组告警的配置要点。
概述
ClickHouse 常用来存海量的日志、埋点和明细数据。把它接成告警数据源后,可以直接写 SQL 在上面做告警判定——不必先把数据加工成指标。
和其它 SQL 类数据源一样,理解 ClickHouse 告警的关键是:SQL 返回的是表结构结果,要靠「值字段」和「标签字段」映射成告警引擎能判定的时序数据。
| 字段 | 必填 | 说明 |
|---|---|---|
| 数据源类型 / 数据源 | 是 | 选 ClickHouse 类型并选中已接入的实例 |
| 查询条件 | 是 | SQL 语句,如 SELECT count(*) as count FROM db_name.table_name |
| 值字段(辅助配置) | 是 | SQL 结果的哪一列作为数值,用 $A.<列名> 在告警条件里引用 |
| 标签字段(辅助配置) | 否 | SQL 结果的哪些列作为告警事件的标签,通常是 GROUP BY 的分组列 |
| 告警条件 | 是 | 基于值字段写告警表达式,如 $A.count > 100 |
| 执行频率 | 是 | 多久跑一次 SQL |
| 持续时长 | 是 | 满足条件持续多久才触发 |
值字段是数值、标签字段是字符串——这个区分决定了每列在告警表达式里能做什么运算,详见 告警表达式语法 的核心概念。
下面按实际使用场景介绍。
场景一:统计一个数值判阈值
最简单的模式:用聚合函数算出一个数,超过阈值就告警。「最近 5 分钟错误日志超过 1000 条」:
SELECT count(*) AS err_count
FROM logs.app_log
WHERE level = 'ERROR'
AND event_time > now() - INTERVAL 5 MINUTE;
- 值字段选
err_count; - 告警条件写
$A.err_count > 1000。
写完 SQL 点「数据预览」,确认返回的列名和值符合预期,再配阈值。
场景二:GROUP BY 分组告警
想让每个服务、每个接口单独告警,用 GROUP BY 分组,并把分组列设为标签字段:
SELECT service AS service, count(*) AS err_count
FROM logs.app_log
WHERE level = 'ERROR'
AND event_time > now() - INTERVAL 5 MINUTE
GROUP BY service;
- 值字段选
err_count,标签字段选service; - 告警条件
$A.err_count > 100。
SQL 返回几行就有几条"伪时序",告警引擎逐行独立判定——每个 service 各自触发独立的告警事件,事件标签里带对应的 service。
场景三:多查询混合判定
对比多条 SQL 的结果,比如算错误率。添加 $A、$B 两条查询后,告警条件写:
$B.err_count / ($A.total_count + $B.err_count) * 100 > 5
更多 SQL 类业务告警的表达式写法(算术、字符串匹配、时间戳新鲜度等),见 MySQL 告警举例——表达式语法与数据源无关,同样适用于 ClickHouse。
常见问题
Q1:SQL 返回多行会怎样?
A:每行作为一条独立"伪时序",逐行判定告警。返回 10 行就最多产生 10 条告警事件。用 GROUP BY + 标签字段控制分组粒度。
Q2:值字段和标签字段怎么选?
A:要做数值比较的列(计数、耗时、金额)选值字段;要作为告警分组维度或事件标签的列(服务名、接口、状态码)选标签字段。
Q3:查询扫描的数据量太大怎么办?
A:ClickHouse 上的告警查询会周期性执行,务必:SQL 里用分区/主键列限定时间范围(如 event_time > now() - INTERVAL 5 MINUTE),避免全表扫;把执行频率调到与查询代价匹配的水平;必要时用物化视图预聚合。
Q4:告警条件的表达式语法和其它数据源一样吗?
A:完全一样,都是同一套告警表达式。区别只在查询语言(SQL vs PromQL)和数据形态(表 vs 时序)。
参考资料
- 告警表达式语法
- MySQL 告警举例(SQL 类表达式写法通用)
- MySQL 查询
- 告警规则基础配置