分析时序数据:如何从 InfluxQL 迁移到 SQL
GreptimeDB 的主要查询接口是 SQL 语言。当用户利用 InfluxDB 行协议将数据写入 GreptimeDB 之后,立即就有一个问题是如何分析写入的数据。尤其是,如何将现有的 InfluxQL 查询迁移到 SQL 查询。
为了回答这个问题,本文概述了 InfluxDB 上的查询语言(InfluxQL 和 Flux)与 SQL 的差别,以及从 InfluxQL 迁移到 SQL 的最佳实践。
查询语言简介
InfluxQL
InfluxQL 是 InfluxDB V1 自创的查询语言,大体上模仿了 SQL 的结构,以下是一些 InfluxQL 查询的示例:
InfluxDB 设计开发的年代,数据库开发的人才远远不像今天一样充足。因此,尽管 InfluxQL 努力靠近 SQL 的语法,但是在当时,以关系代数为支撑实现基本的 SQL 能力并添加时序查询扩展是比较困难的。
InfluxQL 转而实现了大量专为时序数据分析设计的功能和运算符。例如,所有查询会默认返回时间列并按升序排序,所有查询必须带有 field 列才会返回结果,面向时间线粒度设计的特殊查询语法,等等。
基本上,InfluxQL 就是 InfluxDB 对以数值指标为主的时序数据分析需求的直接翻译。随着 InfluxDB 产品的发展,InfluxQL 还支持连续查询和指定保留策略,以实现某种程度的实时数据处理。
虽然 InfluxQL 在 InfluxDB V2 中也能使用,但是由于 InfluxDB V2 主推 Flux 查询语言,使用 InfluxQL 会面临一系列模型失配导致的额外挑战。
Flux
Flux 是 InfluxDB V2 自创的查询语言。不同于 InfluxQL 模仿 SQL 的语法结构,Flux 的语法属于 DataFrame 的流派。Elixir 的开发者会对 Flux 的语法感到亲切,以下是 Flux 查询的示例:
从设计理念上说,Flux 的目的是要支持各种数据源上的时序数据的联合分析。它允许用户从时序数据库(InfluxDB)、关系型数据库(PostgreSQL 或 MySQL),以及 CSV 文件上获取数据,然后进行分析。例如,可以用 sql.from 或 csv.from 相关的语法从数据源拉取数据,替代上述示例中 from(bucket) 的部分,后接其他分析算子。
Flux 语言只能在 InfluxDB V2 中使用,V1 上不支持,V3 上被 弃用。原因显而易见:学习成本太高。进一步地,没有专业的语言开发者支持,要在扩展语法的同时修复各种设计实现问题,这几乎是不可负担的工程成本。
SQL
SQL 是数据分析师熟悉的查询语言。它的大名是结构化查询语言(Structured Query Language),理论基础是关系代数。
不同于从业务中生长出来的,专为业务场景定制的方言,SQL 有坚实的理论支持。从 E. F. Codd 发表了经典论文《A Relational Model of Data for Large Shared Data Banks》之后,五十多年来积累在关系型数据库上的研究汗牛充栋。
尽管各家 SQL 数据库都会实现独特的扩展,有时会让用户挺摸不着头脑,但是在关系代数理论的支持下,基本的查询分析能力,每一个 SQL 数据库都能一致实现。如果在十几二十年前,或许 Data Infra 的舆论场还会出现 SQL 已死的论调。但是在今天,毫无疑问 SQL 作为数据分析的默认选择已经王者归来。几十年来,SQL 不断地被改进和扩展,并经由一系列久经考验的实现推广,在全球范围内得到了广泛采用。
InfluxDB V3 号称实现了 SQL 查询的支持,并在该版本中推荐用户使用 SQL 分析时序数据。GreptimeDB 在技术选型上和 InfluxDB V3 不谋而合,率先自主实现了面向时序数据的 SQL 数据库,并在多个严肃生产环境当中部署使用。
在 GreptimeDB 上可以用 标准 SQL 执行查询:
SQL 的理论支持帮助新的时序数据库可靠地实现复杂的查询逻辑,以及完成日常数据管理任务。SQL 丰富的生态,也使得新的时序数据库能够快速接入到数据分析的技术栈上。例如,此前制作的输入行为分析示例,就利用 GreptimeDB 支持 MySQL 协议这点,零成本地集成到 Streamlit 上实现了可视化。
时序分析的挑战
SQL
虽然 SQL 有着理论支持强大和分析生态丰富两个核心优势,但是在传统的 SQL 数据库在处理时序数据时仍然会面临一系列的挑战,其中最突出的就是数据规模带来的挑战。
时序数据的价值密度大多数时候非常低。设备上传的信息大部分时候你都不会专门去看,应用上报自己状态健康的数据,也不需要额外留意。因此,存储时间数据的成本效率就至关重要。如何利用新时代的云共享存储降低成本,通过针对时序数据的极致压缩来减少数据本身需要的容量,都是时序数据库需要研究的课题。
此外,如何高效地从大量时序数据中提取关键信息,很多时候确实需要特定的查询扩展来优化。GreptimeDB 支持 RANGE QUERY 以帮助用户分析特定时间窗口下的数据聚合就是一个例子。
Flux
毋庸赘言,学习成本就杀死了这个方言。同样,复述一遍前文的观点,作为一个单一提供商独木难支的方言,其语言本身的健壮性,性能优化能做的投入,以及生态的开发,都面临巨大的挑战,更不用说现在这个唯一提供商还放弃了继续发展 Flux 方言。这下已死勿念了。
InfluxQL
虽然 InfluxQL 查询写起来有些像 SQL 的语法,但是其中细微的区别还是非常让人恼火的。而且,即使努力的 Cosplay SQL 的语法,InfluxQL 从根上还是一个从主要关注指标的时序分析业务需求长出来的方言。它在后续开发和维护成本上的挑战和 Flux 不会有本质的差别。
例如,InfluxQL 不支持 JOIN 查询。虽然你可以写类似 SELECT * FROM "h2o_feet", "h2o_pH"
这样的查询,但是它的含义是分别读出两个 measurement 上的数据(😅):
此外,虽然 InfluxDB V3 在强烈的用户呼声下支持了 InfluxQL 以帮助用户逐步迁移到新版本,但是 InfluxDB V3 主推的还是基于 SQL 的查询方案。换句话说,大胆点判断,InfluxQL 也是一个已死勿念的方言。
如何迁移到 SQL 分析
今天,仍有许多存量时序数据分析逻辑是用 InfluxQL 写成的。本节介绍 InfluxQL 跟 SQL 的核心不同,从而说明如何从 InfluxQL 迁移到 SQL 分析。
时间列
应用逻辑迁移当中,最重要的一个区别就是 SQL 对时间列没有特殊的处理,而 InfluxQL 会默认返回时间列,且结果按时间戳升序排列。SQL 查询需要显式指定时间列以在结果集中包含时间戳,也需要手动指定排序逻辑。
数据写入时,InfluxQL 会默认自动用当前时间填充时间列,而 SQL 必须手动指定时间列的值。如果是当前时间,也需要明确写出:
InfluxQL 不支持一个 INSERT 语句插入多列,SQL 数据库通常支持一个 INSERT 语句插入多列:
此外,InfluxQL 查询使用 tz() 函数指定查询的时区,而 SQL 通常有其他设定时区的方式。GreptimeDB 支持 MySQL 和 PostgreSQL 设置时区的语法。
时间线
InfluxQL 实现了时间线粒度的查询语法,例如 SLIMIT 和 SOFFSET 等。
SLIMIT 会限制结果集中单个时间列返回数据的数量,例如 SLIMIT 1 意味着每个时间列最多返回一个符合过滤条件的结果。
SQL 不是专为时序数据分析设计的,因此需要一些取巧的手段。例如:
这个查询返回以 host 为标签区分的时间列,每个时间列唯一一个结果:
时间间隔
InfluxQL 的时间间隔语法形如 1d
或 12m
等,SQL 当中时间间隔有标准语法:
数据列和标签列
InfluxQL 从模型上就区分了数据列和标签列,只 SELECT 了标签列的查询是查不出数据的。此外,InfluxQL 支持 ::field 和 ::tag 后缀来指定数据列或标签列,并由此支持同名的数据列和标签列。
SQL 标准不区分数据列和标签列,都是普通的一列。不过在具体系统实现上,可能会对概念做一些映射。例如,GreptimeDB 的数据模型 就区分了时间列、标签列和数据列,并有对应的映射规则。
(图 1 :GreptimeDB 的数据架构)
函数名称
部分函数的名称未必相同。例如,InfluxQL 当中的 MEAN
函数对应 SQL 当中的 AVG
函数。
其他函数,例如 COUNT
/ SUM
/ MIN
等等,许多还是相同的。
标识符
InfluxQL 的标识符很多时候需要用双引号括起来,而 SQL 则支持无引号的标识符。
值得注意的是,SQL 的标识符默认是大小写不敏感的,如果需要大小写敏感的标识符,则需要用对应的引号括起来。在 GreptimeDB 当中,默认是用双引号括起。但是在 MySQL 或 PostgreSQL 客户端链接上来的时候,会尊重对应方言的语法。
InfluxQL 标识符引号的部分使用区别示例如下:
以上是来自 GreptimeDB JOIN 的示例。GreptimeDB 支持:
INNER JOIN
LEFT JOIN
RIGHT JOIN
FULL OUTER JOIN
时间范围查询
InfluxQL 的 GROUP BY
语句支持传递一个时间间隔,以按照特定长度的时间窗口来聚合数据。
SQL 没有这样特定的查询能力,最接近的应该是 OVER ... PARTITION BY
的语法,但是这个语法还挺难理解的。
GreptimeDB 实现自己的范围查询扩展语法:
JOIN
InfluxQL 不支持 JOIN 查询,SQL 数据库的一个重要甚至是基础能力就是支持 JOIN 查询:
持续聚合
InfluxQL 支持持续聚合,这在 SQL 当中是标准的物化视图(Materialized View)的需求。
不过,物化视图在大部分 SQL 数据库中的实现都比较脆弱,目前仍然是一个有待探索的领域。GreptimeDB 基于数据流引擎实现了持续聚合来支持相关需求。
总结
本文介绍了作为查询语言的 InfluxQL、Flux 和 SQL 之间的差异。虽然 InfluxQL 和 Flux 是 InfluxDB 使用的查询语言,并且专为处理时间序列数据创造,但是 SQL 是关系数据库中广泛使用的查询语言,其可靠的理论基础和丰富的生态集成,让数据分析师能够快速上手,用趁手的工具分析时序数据。
GreptimeDB 原生支持 SQL 查询,欢迎访问我们的主页了解更多信息,或立即创建一个免费的云服务实例开始试用。
关于 Greptime
Greptime 格睿科技专注于为可观测、物联网及车联网等领域提供实时、高效的数据存储和分析服务,帮助客户挖掘数据的深层价值。目前基于云原生的时序数据库 GreptimeDB 已经衍生出多款适合不同用户的解决方案,更多信息或 demo 展示请联系下方小助手(微信号:greptime)。
欢迎对开源感兴趣的朋友们参与贡献和讨论,从带有 good first issue 标签的 issue 开始你的开源之旅吧~期待在开源社群里遇见你!添加小助手微信即可加入“技术交流群”与志同道合的朋友们面对面交流哦~
Star us on GitHub Now: https://github.com/GreptimeTeam/greptimedb
Twitter: https://twitter.com/Greptime
Slack: https://greptime.com/slack
评论