本节摘要:PromQL 是集合导向:一次选多条 series 再聚合;SQL 是表导向:
GROUP BY time_bucket。Influx Flux 管道过滤;QuestDB 标准 SQL +SAMPLE BY。本节用同一监控问题给出四家等价写法,并标注 Remote Write 后的查询归属。
阅读完本节,你应当能够:
sum by 翻译为 Timescale SQL团队混用 Prometheus 采集 + Timescale 长期存 + Grafana 查询——面板报错常是语义没对齐:PromQL 的 ignoring/on 标签匹配,SQL 的 GROUP BY 列,Influx 的 _field 过滤,四套思维需一张对照表。2019 年后 SQL 复兴(Influx IOx、QuestDB、Timescale)让「会 SQL 就会时序」成为可能,但 PromQL 在监控模板库仍占主导。
场景 A:按 service 求 5m QPS
| 引擎 | 写法 |
|---|---|
| PromQL | sum(rate(http_requests_total[5m])) by (service) |
| Timescale | SELECT time_bucket('5m',time), service, sum(cnt)/300.0 FROM ... GROUP BY 1,2 |
| Influx Flux | |> aggregateWindow(every: 5m, fn: sum) |> derivative(...) |
| QuestDB | SELECT ts, service, sum(requests)/300 FROM t SAMPLE BY 5m FILL(PREV) |
场景 B:CPU 使用率 Top 5 host
| 引擎 | 写法 |
|---|---|
| PromQL | topk(5, avg by (host)(rate(cpu_seconds_total[5m]))) |
| Timescale | SELECT host, avg(cpu) ... GROUP BY host ORDER BY 2 DESC LIMIT 5 |
| QuestDB | 同上 SQL + LATEST ON ts PARTITION BY host |
| 维度 | PromQL | SQL(Timescale/QuestDB) |
|---|---|---|
| 数据模型 | labels 集合 | 行 + 列 |
| JOIN 维表 | 弱(需 export) | 原生 JOIN |
| 学习曲线 | 监控工程师熟悉 | 数据分析师熟悉 |
| 生态模板 | kube-prometheus 丰富 | 需自建或转换 |
histogram 在两边都能表达,但写法完全不同,这是迁移时最容易出错的地方:
# Prometheus:由桶计数近似分位数 histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
-- Timescale:用近似分位数聚合函数 SELECT time_bucket('5 min', time), approx_percentile(0.99, duration) FROM http_durations WHERE time > now() - interval '1 hour' GROUP BY 1;
注意两者语义差异:Prometheus 的 histogram_quantile 依赖客户端预分桶(_bucket 指标),Timescale 的 approx_percentile 直接对原始值做近似估计。同样的「P99」在两边的数值可能略有不同——迁移 dashboard 时不要期望逐点重合。
# Prometheus:同比(一周前同期),注意周对齐 sum(rate(http_requests_total[5m] offset 1w)) by (service)
-- Timescale:同一周期的绝对时间窗口 SELECT time_bucket('5 min', time), service, sum(cnt)/300.0 AS qps FROM http_requests WHERE time BETWEEN now() - interval '1 week' - interval '5 min' AND now() - interval '1 week' GROUP BY 1, 2;
PromQL 的 offset 1w 是「相对位移」,SQL 必须把位移换算成绝对时间范围;若目标周数据存在缺失 chunk,SQL 侧会产生空桶,而 PromQL 会把空桶隐式跳过——这就是「周对齐空桶导致假同比」的根源。
跨引擎查询对不上的另一个高频来源是窗口对齐规则不同:
| 引擎 | 默认对齐 | 空桶处理 | 备注 |
|---|---|---|---|
| PromQL | 查询步长(Grafana step) | 无样本不返回 | 滑动窗口重叠 |
| time_bucket | UTC 整点 | 无行即缺 | 可传 offset |
| QuestDB SAMPLE BY | 时间戳起算 | 需 FILL 显式指定 | ALIGN TO CALENDAR |
| Flux aggregateWindow | 开始时间起算 | createEmpty 可配 | 固定桶 |
Prometheus → VictoriaMetrics/Influx/Timescale 后,查询可在后端用 SQL 或 PromQL API(VM 兼容 PromQL)。OpenTelemetry collector 则可一次 export 多后端,避免双写逻辑分叉。

| 需求 | 建议 |
|---|---|
| K8s 默认 dashboard | 保持 PromQL |
| 与 ERP 维表 JOIN | Timescale/QuestDB SQL |
| 跨集群联邦 | Prometheus federation 或 VM 单点查询 |
| 多租户隔离 | label/tenant_id + RLS(Timescale) |
Migrating 查询:Grafana 同一 panel 可切 datasource——迁移期双写双查,对比 rate 曲线是否重合(注意 step 与 alignment)。
如果你要从「PromQL 为主」迁移到「SQL 为主」,建议按三个台阶走:第一步,保留 Prometheus 采集不动,把长期存储切到 SQL 引擎(Timescale/QuestDB),Grafana 面板逐步切 datasource;第二步,对高频面板做「PromQL vs SQL」双查询对比,确认语义一致后再下线 PromQL 版;第三步,把 recording rule 平移成 continuous aggregate 或物化视图。整个迁移期以「双写双查」为底线,避免一次性切换造成的监控空洞。
⚠️ 常见坑:把 PromQL
offset 1w同比直接写成 SQL 而不处理缺失 chunk——周对齐空桶导致假同比。
💡 关键直觉:PromQL 擅长「many series → one graph」;SQL 擅长「one table → join & window」——混合架构很常见,不是二选一。
sum(rate(http_requests_total[5m])) by (service) 翻译成 Timescale SQL,注意单位换算。offset 1w 同比为什么不能原样搬进 SQL?后续章节将讨论写入路径性能与四大产品选型决策表(第4–6章,待续)。