Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

基于 SQL 的可视化

ClickStack 支持基于原始 SQL 查询的可视化。这让你能够完全控制查询逻辑,同时仍可与仪表板级别的时间范围、过滤器和图表渲染集成。

当你需要实现内置 Chart Explorer 不支持的功能时,基于 SQL 的可视化就非常有用——例如,关联多个表,或构建图表构建器不支持的复杂聚合。

创建基于 SQL 的可视化

要创建基于 SQL 的可视化,请打开仪表板卡片编辑器并选择 SQL 选项卡。

SQL 编辑器按钮

接下来:

  1. 选择一个要用于运行查询的 ClickHouse 连接
  2. 也可以选择一个 Source —— 这样就能通过 $__filters 宏将仪表板级过滤器应用到图表。
  3. 在编辑器中编写 SQL 查询,使用查询参数和宏与仪表板的时间范围、过滤器及变量集成。
  4. 点击 play 按钮预览结果,然后点击 Save

查询参数

查询参数 允许你在 SQL 中引用当前仪表板的时间范围和粒度。它们使用 ClickHouse 的参数化查询语法:{paramName:Type}

可用参数

可用参数取决于图表类型:

折线图和堆叠条形图:

参数 类型 描述
{startDateMilliseconds:Int64} Int64 仪表板日期范围的开始时间 (自纪元以来的毫秒数)
{endDateMilliseconds:Int64} Int64 仪表板日期范围的结束时间 (自纪元以来的毫秒数)
{intervalSeconds:Int64} Int64 时间分桶大小 (以秒为单位,基于粒度)
{intervalMilliseconds:Int64} Int64 时间分桶大小 (以毫秒为单位,基于粒度)

表格、饼图和数值图表:

参数 类型 描述
{startDateMilliseconds:Int64} Int64 仪表板日期范围的开始时间 (自纪元以来的毫秒数)
{endDateMilliseconds:Int64} Int64 仪表板日期范围的结束时间 (自纪元以来的毫秒数)

宏是会展开为常见 ClickHouse SQL 表达式的简写。它们以前缀 $__ 开头,并会在查询发送到 ClickHouse 之前完成替换。

时间边界宏

这些宏返回一个 ClickHouse 表达式,表示 仪表板 的开始时间或结束时间。它们不接受任何参数。

Macro 展开为 列类型
$__fromTime toDateTime(fromUnixTimestamp64Milli({startDateMilliseconds:Int64})) DateTime
$__toTime toDateTime(fromUnixTimestamp64Milli({endDateMilliseconds:Int64})) DateTime
$__fromTime_ms fromUnixTimestamp64Milli({startDateMilliseconds:Int64}) DateTime64
$__toTime_ms fromUnixTimestamp64Milli({endDateMilliseconds:Int64}) DateTime64
$__interval_s {intervalSeconds:Int64} Int64

时间过滤宏

这些宏会生成一个 WHERE 子句片段,用于按仪表板的时间范围过滤某一列。

Macro Description
$__timeFilter(column) 按仪表板时间范围过滤 DateTime
$__timeFilter_ms(column) 按仪表板时间范围过滤 DateTime64 (毫秒) 列
$__dateFilter(column) 按仪表板时间范围过滤 Date
$__dateTimeFilter(dateCol, timeCol) 使用单独的 Date 列和 DateTime 列进行过滤
$__dt(dateCol, timeCol) $__dateTimeFilter 的别名

$__timeFilter(TimestampTime)展开示例

TimestampTime >= toDateTime(fromUnixTimestamp64Milli({startDateMilliseconds:Int64}))
AND TimestampTime <= toDateTime(fromUnixTimestamp64Milli({endDateMilliseconds:Int64}))

时间间隔宏

这些宏会将时间戳列分组到与仪表板粒度相匹配的时间间隔中。它们通常用于时间序列图表的 SELECTGROUP BY 子句。仅适用于 折线图 和 Stacked-bar 可视化。

Macro Description
$__timeInterval(column) DateTime 列按 intervalSeconds 的时间间隔分组
$__timeInterval_ms(column) DateTime64 列按 intervalMilliseconds 的时间间隔分组

$__timeInterval(TimestampTime)展开示例

toStartOfInterval(toDateTime(TimestampTime), INTERVAL {intervalSeconds:Int64} second)

仪表板过滤器宏

Macro Description
$__filters 替换为仪表板级过滤条件 (需要选择一个 Source)

当在图表中选择了 Source 且仪表板过滤器已启用时,$__filters 会展开为对应的 SQL WHERE 条件。未选择 Source 或未应用任何过滤器时,它会展开为 (1=1),因此始终可以安全地将其包含在 WHERE 子句中。

只有启用了 Broadcast filter condition 的过滤器才会由 $__filters 应用。作为变量公开的过滤器会被显式引用,如下所述。

仪表板变量宏

当仪表板过滤器可用作变量时,可在查询的任何位置引用其选中值。只有属于声明了至少一个变量的仪表板的卡片才能使用这些宏。

描述
$__filter($<variable>) 当为 variable 选择了值时,展开为 toString(<filter expression>) IN ($variable);否则展开为 1=1
$__filter(<expression>, $<variable>) 当为 variable 选择了值时,展开为 <expression> IN ($variable);否则展开为 1=1
$__conditionalAll(<condition>, $<variable>) 当变量有选中值时,展开为 <condition>;否则展开为 1=1

变量值也可直接插值为 $name${name},并可选择指定格式:${name:sqlstring} (默认) 、${name:csv}${name:regex}。在默认格式下,未选择任何值时,直接引用会呈现为 NULL;因此,凡是需要谓词的位置,建议优先使用上述宏。

查询结果的绘制方式

ClickStack 会根据列类型,自动将查询结果中的列映射到图表元素。映射规则因图表类型而异。

折线图和堆叠条形图

角色 列类型 说明
时间戳 第一个 DateDateTime 用作 x 轴。
系列值 所有数值列 每个数值列都会绘制为单独的 series。这些通常是聚合值。
分组名称 String、Map 或 Array 列 可选。分组值不同的行会绘制为单独的 series。

饼图

角色 列类型 描述
切片值 第一个数值列 决定每个切片的大小。
切片标签 String、Map 或 Array 列 可选。每个唯一值都会成为一个切片标签。

数值图表

角色 列类型 描述
数值 第一个数值列 显示第一个数值列第一行的值。

表格图表

所有结果列都会直接显示为表格中的列。

示例

折线图 — 按服务划分的日志计数随时间变化

此查询按服务统计日志事件数,并按与仪表板粒度一致的时间间隔进行分组。

SELECT
  toStartOfInterval(TimestampTime, INTERVAL {intervalSeconds:Int64} second) AS ts,
  ServiceName,
  count() AS count
FROM otel_logs
WHERE TimestampTime >= fromUnixTimestamp64Milli({startDateMilliseconds:Int64})
  AND TimestampTime < fromUnixTimestamp64Milli({endDateMilliseconds:Int64})
  AND $__filters
GROUP BY ServiceName, ts
ORDER BY ts ASC
  • ts (DateTime) 用作 x 轴时间戳。
  • count (numeric) 作为序列值进行绘制。
  • ServiceName (string) 为每个服务生成一条单独的折线。

折线图 — 使用宏

为简洁起见,以下是使用宏编写的同一查询:

SELECT
  $__timeInterval(TimestampTime) AS ts,
  ServiceName,
  count() AS count
FROM otel_logs
WHERE $__timeFilter(TimestampTime)
  AND $__filters
GROUP BY ServiceName, ts
ORDER BY ts ASC

折线图 — 使用仪表板变量

假设仪表板中有一个基于 ServiceNameservice 变量,以及一个基于 SeverityTextseverity 变量,此查询会将图表范围限定为当前选定的服务,并排除选定的严重性级别。当变量未选择任何值时,两个宏都会展开为 1=1,因此在查看者选择值之前,图表不会应用过滤器。

SELECT
  $__timeInterval(TimestampTime) AS ts,
  count() AS count
FROM otel_logs
WHERE $__timeFilter(TimestampTime)
  AND $__filter(ServiceName, $service)
  AND $__conditionalAll(SeverityText NOT IN ($severity), $severity)
GROUP BY ts
ORDER BY ts ASC

堆叠条形图 — 按严重级别统计的错误数

SELECT
  $__timeInterval(TimestampTime) AS ts,
  lower(SeverityText),
  count() AS count
FROM otel_logs
WHERE $__timeFilter(TimestampTime)
  AND lower(SeverityText) IN ('error', 'warn')
  AND $__filters
GROUP BY SeverityText, ts
ORDER BY ts ASC

表格图表 — 最慢的 10 个端点

SELECT
  SpanName AS endpoint,
  avg(Duration) / 1000 AS avg_duration_ms,
  count() AS request_count
FROM otel_traces
WHERE $__timeFilter(Timestamp)
  AND $__filters
GROUP BY SpanName
ORDER BY avg_duration_ms DESC
LIMIT 10

饼图——按服务统计的请求分布

SELECT
  ServiceName,
  count() AS request_count
FROM otel_traces
WHERE $__timeFilter(Timestamp)
  AND $__filters
GROUP BY ServiceName
  • request_count (数值) 决定每个扇区的大小。
  • ServiceName (字符串) 用于标注每个扇区。

数值图表——错误总数

SELECT
  count() AS total_errors
FROM otel_logs
WHERE $__timeFilter(TimestampTime)
  AND SeverityText = 'error'
  AND $__filters

将显示第一行中的数值 total_errors

注意事项

  • 基于 SQL 的可视化会在启用 readonly 模式的情况下执行——仅允许 SELECT 查询。
  • 基于 SQL 的可视化必须且只能包含一条 SQL 查询,不支持多条查询。
  • SQL 编辑器会为查询参数和宏提供自动补全建议。
  • 必须先选择一个 source,才能将 仪表板 过滤器应用到基于 SQL 的可视化中。该 source 应与所查询的表一致,以确保过滤准确。
  • 仪表板变量无需 source——其值来自仪表板的过滤器下拉列表,而非卡片自身的 source。
  • 引用了仪表板变量的 SQL 卡片上的告警,会在所有变量均为空状态时进行评估,而不会使用仪表板中选定的值。
Navigation