DQL VS 其它查询语言¶
写在前面¶
为了帮助大家快速理解和运用 DQL,我们将它与三种常见的查询语言进行对比:PromQL 、LogQL、SQL。
PromQL 是 Prometheus 中用于查询其时序数据的一种查询语言。LogQL 是用于 Grafana Loki 的一种日志查询语言,它借鉴了 PromQL 的语法结构设计,与 PromQL 的写法很相近。SQL 是我们日常使用最多的一种通用查询语言,其语法结构与前两者差异很大(各个不同数据库大同小异,此处以 MySQL 为例)。
注意
SQL 有强大的增、删、查、改能力,此处只摘取其查询功能作为对比。
DQL 初期的语法结构与 PromQL 类似,但随着业务的不断拓展,DQL 逐渐演变出不同的查询功能。它综合了 PromQL 的基本语法结构,同时借鉴了 SQL 语句的一些语法结构以及语义表达,旨在更便于大家编写较为复杂的查询。
下文将从如下几个方面加以说明各个查询语言的差异:
- 基本语法结构
- 支持的常用预定义函数
- 常用查询写法
基本语法结构¶
| 查询语言 | 基本结构 |
|---|---|
| PromQL | 指标 {条件过滤列表} [起始时间:结束时间] |
| LogQL | {stream-selector} log-pipeline |
| SQL | SELECT <column-clause> <FROM-clause> <WHERE-clause> <GROUP-BY-clause> ... |
| DQL | namespace::指标集:(column-clause) [time-range-clause] { WHERE-clause } GROUP-BY-clause ORDER-BY-clause |
PromQL¶
在 Prometheuse 中,相关指标是离散形式组织的。在其查询中,可直接查找对应的指标,如:
此处即查找指标 http_requests_total,通过指定其 label 限制条件(environment 和 method)来过滤数据。
注意
PromQL 称这里的 label 限制条件为 Label Matchers。可简单将其理解为一种 where 条件过滤。
LogQL¶
顾名思义,LogQL 主要用于日志内容查询,如:
{container="query-frontend", namespace="loki-dev"}
|= "metrics.go"
| logfmt
| duration > 10s and throughput_mb < 500
此处 {...} 里面的,LogQL 称之为 Stream Selector,其旨在于划定数据查询范围(类似于 SQL 中的 FROM ... 部分);后半部分则称之为 Log Pipeline,其主要处理日志信息的提取和过滤。
从这里可看出,LogQL 中的 {...} 跟 PromQL 中的 Label Matchers 一样,我们也可将其理解为一种 where 条件过滤。
SQL¶
对于大家最为熟知的查询语言,如果要达到如上俩种效果,简单翻译如下(因存储结构不同,此处只表达大概意思):
SELECT * FROM `loki-dev`
WHERE container="query-frontend" AND
duration > 10s AND
throughput_mb < 500
DQL¶
DQL 本质上是一个查询翻译器,其后台并不直接管理数据的存储和组织。故理论上其可以支持任意类型的存储引擎,如信息数据存储(MySQL/Oracle/ES/Redis 等)、文件存储(HBASE/S3/OSS 等)。目前 DQL 主要用于如下几类数据的查询:
- 时序数据
- 日志数据
- 对象数据
- 应用性能追踪(APM)数据
- 用户行为检测(RUM)数据
- 关键事件数据
- ...
如:
此处,metric 指定了要查询时序数据(可简单理解成 MySQL 中的一个 DB),而 cpu 就是其中的一种指标集(类似于 MySQL 中的 Table),并且指定查找其中的两个字段 usage_system 和 usage_user;接着,{...} 中的表示过滤条件,最后 [...] 表示查询的时间范围:前天到昨天一段时间内,以 1h 为聚合间隔。
更多示例:
# 查询 K8s 中的 pod 对象(object)
object::kubelet_pod:(name, age) { cpu_usage > 30.0 } [10m] BY namespace
# 查找名为 my_service 应用的日志(message 字段)
logging::my_service:(message) [1d]
# 查看应用性能追踪(T 即 tracing)中,持续时间 > 1000us 的 span 数据,并且按照 operation 来分组
T::my_service { duration > 1000 } [10m] BY operation
横向对比¶
基本功能对比¶
| 查询语言 | 主要领域 | 时序查询 | 日志查询 | 时间范围查找 | group by 聚合 |
|---|---|---|---|---|---|
| PromQL | Prometheuse 指标查询 | 支持 | 不支持 | 支持 | 支持 |
| LogQL | 查询日志 | 支持从日志生成指标 | 支持 | 支持 | 支持 |
| SQL | 通用查询语言 | 某些数据库 支持时序存储 |
不适合 | 支持 | 支持 |
| DQL | 观测云全平台数据查询 | 支持 | 支持 | 支持 | 支持 |
周边工具支持¶
| 查询语言 | 注释方式 | HTTP API | Pipeline 切割 | 命令行 |
|---|---|---|---|---|
| PromQL | # 单行注释 |
支持 | 不支持 | promql-cli |
| LogQL | # 单行注释 |
支持 | 支持 | logcli |
| SQL | -- 单行注释或 /* 多行注释 */ |
不支持 | 不支持 | 各种 SQL 客户端,此处不再赘述 |
| DQL | # 单行注释 |
支持 | 不支持(在 DataKit 端已预先切割好) | 需安装DataKit ,再执行查询 |
数据处理函数支持情况¶
常见查询语句写法对比¶
普通数据查询及过滤¶
# LogQL
{ cluster="ops-tools1", namespace="dev", job="query-frontend"}
|= "metrics.go"
!="out of order"
| logfmt
| duration > 30s or status_code!="200"
# PromQL(PromQL 大概不支持普通意义上的 OR 过滤)
http_requests_total{ cluster='ops-tools1', job!='query=frontend', duration > 30s }
# SQL
SELECT * FROM dev
WHERE cluster='ops-tools' AND
job='query=frontend' AND
(duration > 30000000000 OR stataus_code != 200)
# DQL:从语句结构上可看出,DQL 的语义组织跟 SQL 比较接近
L::dev {
cluster='ops-tools',
job='query=frontend',
message != match("out of order")
(duraton > 30s OR stataus_code != 200) # DQL 支持嵌套结构过滤
}
以下是各种 DQL 语句的写法罗列:
# where-clause 可用 AND 来串联,AND 跟 `,' 语义等价
L::dev {
cluster='ops-tools' AND
job='query=frontend' AND
message != match("out of order") AND
(duraton > 30s OR stataus_code != 200)}
# 支持 AS 别名/支持中文变量
metric::cpu:(usage_system AS 系统用量, usage_user AS 用户用量)
# where-cluase 支持 array-list IN 过滤
L::dev {
cluster='ops-tools' AND
job IN [ 'query=frontend', 'query=backend'] AND
message != match("out of order") AND
(duraton > 30s OR stataus_code != 200)
}
# 支持 base64 传值:对于一些复杂的字符串(比如多行),避免头疼的转义
T::dev {
cluster='ops-tools' AND
resourec IN [
'some-raw-string', # 普通字符串
b64'c2VsZWN0ICoKZnJvbSBhYmMKd2hlcmUgeCA+IDAK' # base64 字符串
]
}
带聚合的查询及过滤¶
# LogQL
sum by (org_id) ({source="ops-tools",container="app-dev"} |= "metrics.go" | logfmt | unwrap bytes_processed [1m])
# PromQL
histogram_quantile(0.9, sum by (job, le) (rate(http_request_duration_seconds_bucket[10m])))
# DQL(注意,ops-tools 两边需加上 ``,不然被解析成减法表达式)
L::`ops-tools`:(bytes_processed) {filename = "metrics.go", container="app-dev"} [2m] BY sum(orig_id)
浏览数据情况¶
# LogQL/PromQL 暂未找到类似查询功能
# MySQL
show tables;
show databases;
# DQL
show_measurement() # 查看时序指标集列表
show_object_source() # 查看对象分类列表
show_rum_source() # 查看 RUM 数据分类列表
show_logging_source() # 查看日志分类列表
总结¶
上述内容对几种常见查询语言进行了基础介绍,每种语言都有其特定的应用场景,且功能差异显著。DQL 的设计初衷是提供一种混合存储的查询方案,这使其与其他语言有本质区别。尽管 DQL 没有独立的存储引擎,但其扩展性远超其他语言,契合其混合存储查询的定位。
目前,DQL 正在积极开发和完善中,功能和性能均有较大提升空间。在观测云中,所有数据查询均全面应用 DQL,其功能、性能和稳定性已通过长时间验证。随着观测云产品的持续迭代,DQL 也将不断演进,以满足产品和开发者的需求。