写点什么

分析时序数据:如何从 InfluxQL 迁移到 SQL

  • 2024-11-08
    北京
  • 本文字数:5451 字

    阅读完需:约 18 分钟

分析时序数据:如何从 InfluxQL 迁移到 SQL

GreptimeDB 的主要查询接口是 SQL 语言。当用户利用 InfluxDB 行协议将数据写入 GreptimeDB 之后,立即就有一个问题是如何分析写入的数据。尤其是,如何将现有的 InfluxQL 查询迁移到 SQL 查询。


为了回答这个问题,本文概述了 InfluxDB 上的查询语言(InfluxQL 和 Flux)与 SQL 的差别,以及从 InfluxQL 迁移到 SQL 的最佳实践。

查询语言简介

InfluxQL

InfluxQL 是 InfluxDB V1 自创的查询语言,大体上模仿了 SQL 的结构,以下是一些 InfluxQL 查询的示例:


SELECT * FROM h2o_feet;SELECT * FROM h2o_feet LIMIT 5;SELECT COUNT("water_level") FROM h2o_feet;SELECT "level description", "location", "water_level" FROM "h2o_feet";SELECT *::field FROM "h2o_feet";
复制代码


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 查询的示例:


from(bucket: "example-bucket")    |> range(start: -1d)    |> filter(fn: (r) => r._measurement == "example-measurement")    |> mean()    |> yield(name: "_result")
复制代码


从设计理念上说,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 执行查询


SELECT ts, idc, AVG(memory_util)FROM system_metricsGROUP BY idcORDER BY ts ASC;
复制代码


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 上的数据(😅):


> SELECT * FROM "h2o_feet", "h2o_pH"
name: h2o_feet--------------time level description location pH water_level2015-08-18T00:00:00Z below 3 feet santa_monica 2.0642015-08-18T00:00:00Z between 6 and 9 feet coyote_creek 8.12[...]2015-09-18T21:36:00Z between 3 and 6 feet santa_monica 5.0662015-09-18T21:42:00Z between 3 and 6 feet santa_monica 4.938
name: h2o_pH------------time level description location pH water_level2015-08-18T00:00:00Z santa_monica 62015-08-18T00:00:00Z coyote_creek 7[...]2015-09-18T21:36:00Z santa_monica 82015-09-18T21:42:00Z santa_monica 7
复制代码


此外,虽然 InfluxDB V3 在强烈的用户呼声下支持了 InfluxQL 以帮助用户逐步迁移到新版本,但是 InfluxDB V3 主推的还是基于 SQL 的查询方案。换句话说,大胆点判断,InfluxQL 也是一个已死勿念的方言。

如何迁移到 SQL 分析

今天,仍有许多存量时序数据分析逻辑是用 InfluxQL 写成的。本节介绍 InfluxQL 跟 SQL 的核心不同,从而说明如何从 InfluxQL 迁移到 SQL 分析。

时间列

应用逻辑迁移当中,最重要的一个区别就是 SQL 对时间列没有特殊的处理,而 InfluxQL 会默认返回时间列,且结果按时间戳升序排列。SQL 查询需要显式指定时间列以在结果集中包含时间戳,也需要手动指定排序逻辑。


-- InfluxQLSELECT "location", "water_level" FROM "h2o_feet";-- SQLSELECT ts, location, water_level FROM h2o_feet ORDER BY ts ASC;
复制代码


数据写入时,InfluxQL 会默认自动用当前时间填充时间列,而 SQL 必须手动指定时间列的值。如果是当前时间,也需要明确写出:


-- InfluxQLINSERT INTO "measurement" (tag, value) VALUES ('my_tag', 42);-- SQLINSERT INTO measurement (ts, tag, value) VALUES (NOW(), 'my_tag', 42);
复制代码


InfluxQL 不支持一个 INSERT 语句插入多列,SQL 数据库通常支持一个 INSERT 语句插入多列:


INSERT INTO measurement (ts, tag, value) VALUES (NOW(), 'my_tag_0', 42), (NOW(), 'my_tag_1', 42);
复制代码


此外,InfluxQL 查询使用 tz() 函数指定查询的时区,而 SQL 通常有其他设定时区的方式。GreptimeDB 支持 MySQLPostgreSQL 设置时区的语法。

时间线

InfluxQL 实现了时间线粒度的查询语法,例如 SLIMIT 和 SOFFSET 等。


SLIMIT 会限制结果集中单个时间列返回数据的数量,例如 SLIMIT 1 意味着每个时间列最多返回一个符合过滤条件的结果。


SQL 不是专为时序数据分析设计的,因此需要一些取巧的手段。例如:


SELECT DISTINCT ON (host) * FROM monitor ORDER BY host, ts DESC;
复制代码


这个查询返回以 host 为标签区分的时间列,每个时间列唯一一个结果:


+-----------+---------------------+------+--------+| host      | ts                  | cpu  | memory |+-----------+---------------------+------+--------+| 127.0.0.1 | 2022-11-03 03:39:58 |  0.5 |    0.2 || 127.0.0.2 | 2022-11-03 03:39:58 |  0.2 |    0.3 |+-----------+---------------------+------+--------+
复制代码

时间间隔

InfluxQL 的时间间隔语法形如 1d12m 等,SQL 当中时间间隔有标准语法:


INTERVAL '1 DAY'INTERVAL '1 YEAR 3 HOURS 20 MINUTES'
复制代码

数据列和标签列

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 实现自己的范围查询扩展语法


SELECT     ts,     host,     avg(cpu) RANGE '10s' FILL LINEARFROM monitorALIGN '5s' TO '2023-12-01T00:00:00' BY (host) ORDER BY ts ASC;
复制代码

JOIN

InfluxQL 不支持 JOIN 查询,SQL 数据库的一个重要甚至是基础能力就是支持 JOIN 查询:


-- Select all rows from the system_metrics table and idc_info table where the idc_id matchesSELECT a.* FROM system_metrics a JOIN idc_info b ON a.idc = b.idc_id;
-- Select all rows from the idc_info table and system_metrics table where the idc_id matches, and include null values for idc_info without any matching system_metricsSELECT a.* FROM idc_info a LEFT JOIN system_metrics b ON a.idc_id = b.idc;
-- Select all rows from the system_metrics table and idc_info table where the idc_id matches, and include null values for idc_info without any matching system_metricsSELECT b.* FROM system_metrics a RIGHT JOIN idc_info b ON a.idc = b.idc_id;
复制代码

持续聚合

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

官网:https://greptime.cn/

文档:https://docs.greptime.cn/

Twitter: https://twitter.com/Greptime

Slack: https://greptime.com/slack

LinkedIn: https://www.linkedin.com/company/greptime/

用户头像

专注于 Infra 技术分享 2022-09-23 加入

分布式、高性能、存储计算分离的开源云原生时序数据库

评论

发布
暂无评论
分析时序数据:如何从 InfluxQL 迁移到 SQL_sql_Greptime 格睿科技_InfoQ写作社区