Sentry 监控 - Snuba 数据中台架构(SnQL 查询语言简介)
阅读原文时间:2021年11月29日阅读:1

本文描述了 Snuba 查询语言 (SnQL)。

以下是 SnQL 的查询结构:

MATCH simple | join | subquery
SELECT [expressions] | [aggregations BY expressions]
ARRAY JOIN [column]
WHERE condition [[AND | OR] condition]*
HAVING condition [[AND | OR] condition]*
ORDER BY expressions ASC|DESC [, expressions ASC|DESC]*
LIMIT expression BY n
LIMIT n
OFFSET n
GRANULARITY n
TOTALS boolean

这些查询作为字符串发送到 /:dataset/snql 端点,编码为以下格式的 JSON body

{
    "query": "<query>",
    "dataset": "<dataset>",
    "consistent": bool,
    "turbo": bool,
    "debug": bool,
}

数据集(dataset)通过查询使用的 url 隐含。在 JSON 主体中,除了 query 之外的所有字段都是可选的。

我们的数据模型由实体图表示。该子句标识了我们正在查询的子图(subgraphs)的模式。目前支持三种类型的 MATCH 子句:

Simple:

MATCH (<entity> [SAMPLE n])

这相当于我们当前的所有查询。 这是从单个实体(事件、事务等)查询数据。可以通过将其与实体一起添加来向查询添加可选 sample

例如:MATCH (events)

Subquery:

MATCH { <query> }

花括号内可以是另一个完整的 SQL 查询。子查询的 SELECT/BY 子句中的任何内容都将使用指定的别名在外部查询中公开。

例如:

MATCH {
    MATCH (transactions)
    SELECT avg(duration) AS avg_d BY transaction
}
SELECT max(avg_d)

Join(连接):

MATCH (<alias>: <entity> [SAMPLE n]) -[<join>]-> (<alias>: <entity> [SAMPLE n])

一个 join 代表一个多节点子图(subgraph),是一个包含不同节点之间的多个关系的子图。目前支持节点之间的 1..nn..11..1 有向关系。

对于 JOIN,每个实体都必须有一个别名,这是一个唯一的字符串。 抽样(Sampling)也可以应用于 join 中的任何实体。<join> 是在 Snuba 中的 Entity 中指定的字符串,是一组 join 条件的简写。可以有多个 join 子句,用逗号分隔。

例如:

MATCH
    (e: events) -[grouped]-> (g: groupedmessage),
    (e: events) -[assigned]-> (a: groupassignee)
SELECT count() AS tot BY e.project_id, g.id
WHERE a.user_id = "somebody"

join 类型(left/inner)和 join key 是数据模型的一部分,而不是查询的一部分。它们被硬编码在实体代码中。 这是因为没有实体可以安全地与底层数据库的分布式版本中的任何其他实体连接。

match 子句提供给 where 子句的元组(tuple)看起来与传统 join 子句生成的元组完全一样:

[
    {"e.project_id": 1,  "g.id": 10}
    {"e.project_id": 1,  "g.id": 11}
    {"e.project_id": 2,  "g.id": 20}
    ...
]

该子句指定应在输出中返回哪些结果。如果存在聚合(aggregation),则 BY 子句中的所有内容都被视为分组 key。 如果我们想要聚合整个结果集,则可以在没有 BY 子句的情况下进行聚合,但在这种情况下,SELECT 中只能包含聚合。即使有 BY 子句,空的 SELECT 子句也是无效的。

SELECT 子句中的表达式可以是算术函数者的任意组合。 如果查询是 join,则每一列都必须有一个符合条件的别名,该别名与 MATCH 子句中的实体别名之一匹配。

这是在聚合之前发生的查询的过滤器(如 SQL 中的 WHERE)。

条件是 LHS OP RHS* 形式的中缀表达式,其中 LHSRHS字面值表达式OP 指的是一个特定的运算符比较两个值。 这些运算符是 =!=<<=>>=INNOT INLIKENOT LIKEIS NULLIS NOT NULL 之一。请注意,当使用像 IS NULL 这样的运算符时,RHS 是可选的。

可以使用布尔关键字 ANDOR 组合条件。它们也可以使用 () 进行分组。

WHERE 子句一样工作,但它在 SELECT 子句中声明的聚合之后应用。 所以我们可以在这里对聚合函数的结果应用条件。

指定对结果集进行排序的表达式。

不言自明,它们采用整数并在 Clickhouse 查询中设置相应的值。 如果查询未指定 limitoffset,它们将分别默认为 10000

一个整数,表示对基于时间的结果进行分组的粒度。

如果设置为 True,来自 Snuba 的响应将有一个 “totals” key,其中包含所有选定行的总值。

如果 MATCH 子句中的节点未提供采样率,则可以在此处指定。 在这种情况下,Snuba 会将 sample right 分配给查询中的节点之一。sample 可以是介于 01 之间的浮点数,表示要采样的行的百分比。

或者它可以是一个大于 1 的整数,表示要采样的行数。