天工开物 #14 分析时序数据:从 InfluxQL 到 SQL 的演变

近年来,时序数据的增长是 Data Infra 领域一个不容忽视的趋势。这主要得益于万物互联带来的自然时序数据增长,以及软件应用上云和自身复杂化后的可观测性需求。前者可以认为是对联网设备的可观测性,而可观测性主要就建构在设备或应用不断上报的指标和日志等时序数据上。

分析时序数据的演变史几乎是大数据分析演变史的复现,即一开始都是把数据存在关系型数据库上,使用 SQL 分析;而后由于规模增长的速度超过传统技术增长,经历了一个折衷技术的歧出;最终,用户在 SQL 强大的理论框架和生态支持的影响下,回到解决了规模问题的 SQL 方案上来。

对于时序数据来说,这一歧出造成了大量时序数据库自创方言。其中以 InfluxDB 在 V1 版本创造了 InfluxQL 方言,在 V2 版本创造了 Flux 方言,又在 V3 里开始主推 SQL 的演变过程最为有趣。

查询语言简介

InfluxQL

InfluxQL[1] 是 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 会面临一系列模型失配导致的额外挑战[2]

Flux

Flux[3] 是 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.fromcsv.from 相关的语法从数据源拉取数据,替代上述示例中 from(bucket) 的部分,后接其他分析算子。

Flux 语言只能在 InfluxDB V2 中使用,V1 上不支持,V3 上被弃用[4]。原因想必大家看完上面这个例子也可以想象:学习成本巨高。更不用说没有专业的语言开发者支持,要在扩展语法的同时修复各种设计实现问题,这几乎是不可负担的工程成本。

SQL

SQL 大家耳熟能详了。它的大名是结构化查询语言(Structured Query Language),理论基础是关系代数。

不同于从业务中生长出来的,专为业务场景定制的方言,SQL 有坚实的理论支持。从 E. F. Codd 发表了经典论文 A Relational Model of Data for Large Shared Data Banks 之后,五十多年来积累在关系型数据库上的研究汗牛充栋。

尽管各家 SQL 数据库都会实现独特的扩展,有时让用户也挺摸不着头脑,但是在关系代数理论的支持下,基本的查询分析能力,每一个 SQL 数据库都能一致实现。如果在十几二十年前,或许 Data Infra 的舆论场还会出现 SQL 已死或者 NoSQL 才是未来的论调。但是在今天,毫无疑问 SQL 作为数据分析的默认选择已经王者归来。几十年来,SQL 不断地被改进和扩展,并经由一系列久经考验的实现推广,在全球范围内得到了广泛采用。

InfluxDB V3 号称实现了 SQL 查询的支持,并在该版本中推荐用户使用 SQL 分析时序数据。GreptimeDB 在技术选型上和 InfluxDB V3 不谋而合,率先自主实现了面向时序数据的 SQL 数据库,并在多个严肃生产环境当中部署使用。

抛开时序查询扩展不谈,在 GreptimeDB 上可以用标准 SQL 执行查询[5]

SELECT idc, AVG(memory_util) FROM system_metrics GROUP BY idc;

SQL 的理论支持帮助新的时序数据库可靠地实现复杂的查询逻辑,以及完成日常数据管理任务。SQL 丰富的生态,也使得新的时序数据库能够快速接入到数据分析的技术栈上。例如,此前制作的输入行为分析示例[6],就利用 GreptimeDB 支持 MySQL 协议这点,零成本地集成到 Streamlit 上实现了可视化。

时序分析的挑战

SQL

虽然 SQL 有着理论支持强大和分析生态丰富两个核心优势,但是在传统的 SQL 数据库在处理时序数据时仍然会面临一系列的挑战,其中最突出的就是数据规模带来的挑战。

时序数据的价值密度大多数时候非常低。设备上传的信息大部分时候你都不会专门去看,应用上报自己状态健康的数据,也不需要额外留意。因此,存储时间数据的成本效率就至关重要。如何利用新时代的云共享存储降低成本,通过针对时序数据的极致压缩来减少数据本身需要的容量,都是时序数据库需要研究的课题。

此外,如何高效地从大量时序数据中提取关键信息,很多时候确实需要特定的查询扩展来优化。GreptimeDB 支持 RANGE QUERY[7] 以帮助用户分析特定时间窗口下的数据聚合就是一个例子。

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_level
2015-08-18T00:00:00Z   below 3 feet           santa_monica        2.064
2015-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.066
2015-09-18T21:42:00Z   between 3 and 6 feet   santa_monica        4.938


name: h2o_pH
------------
time                   level description   location       pH   water_level
2015-08-18T00:00:00Z                       santa_monica   6
2015-08-18T00:00:00Z                       coyote_creek   7
[...]
2015-09-18T21:36:00Z                       santa_monica   8
2015-09-18T21:42:00Z                       santa_monica   7

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

注意 InfluxQL 是查询方言,不包括 InfluxDB 行协议(Line Protocol)的部分。InfluxDB 行协议是一个简洁、完整、高效的数据写入接口。它几乎没有再开发和维护的成本,并且通过 Telegraf 的插件生态,能够快速跟一系列数据上报方案做集成。

如何迁移到 SQL 分析

上文提到,InfluxDB V3 仍然支持 InfluxQL 的核心原因是用户需求。诚然,InfluxDB 过去很长一段时间可说是时序数据库的代名词,并且现在仍然是 DB-Engines 上时序数据分类中最高影响力的数据库。因此,不少时序数据分析的用户现有的分析逻辑是用 InfluxQL 写成的。

这里介绍 InfluxQL 跟 SQL 的核心不同,从而说明如何从 InfluxQL 迁移到 SQL 分析。

时间列

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

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

-- InfluxQL
INSERT INTO "measurement" (tag, value) VALUES ('my_tag', 42);
-- SQL
INSERT 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 支持 MySQL[8] 和 PostgreSQL[9] 设置时区的语法。

时间线

InfluxQL 有一些时间线粒度的查询语法,例如 SLIMITSOFFSET 等。

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 的数据模型[10]就区分了时间列、标签列和数据列,并有对应的映射规则。

ece15747a8aed679407dae948902f449.png

GreptimeDB 的数据模型

函数名称

部分函数的名称未必相同。例如,InfluxQL 当中的 MEAN 函数对应 SQL 当中的 AVG 函数。

其他函数,例如 COUNT / SUM / MIN 等等,许多还是相同的。

标识符

InfluxQL 的标识符很多时候需要用双引号括起来,而 SQL 则支持无引号的标识符。

值得注意的是,SQL 的标识符默认是大小写不敏感的,如果需要大小写敏感的标识符,则需要用对应的引号括起来。在 GreptimeDB 当中,默认是用双引号括起。但是在 MySQL 或 PostgreSQL 客户端链接上来的时候,会尊重对应方言的语法。

InfluxQL 标识符引号的部分使用区别示例如下:

InfluxQLSQL
WHERE("value") > 42where value_col > 42
GROUP BY "tag"GROUP BY tag_col
SELECT MEAN("value") FROM "measurement"SELECT AVG(value_col) FROM measurement

JOIN

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

-- Select all rows from the system_metrics table and idc_info table where the idc_id matches
SELECT 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_metrics
SELECT 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_metrics
SELECT b.* FROM system_metrics a RIGHT JOIN idc_info b ON a.idc = b.idc_id;

以上是来自 GreptimeDB JOIN[11] 的示例。目前时序数据库在 JOIN 查询上支持最全的应该是 QuestDB[12] 数据库。

时间范围查询

InfluxQL 的 GROUP BY 语句支持传递一个时间间隔,以按照特定长度的时间窗口来聚合数据。

SQL 没有这样特定的查询能力,最接近的应该是 OVER ... PARTITION BY 的语法,但是这个语法还挺难理解的。

支持 SQL 的时序数据库大多会实现自己的范围查询扩展:

  • GreptimeDB RANGE QUERY[13]

  • TimescaleDB Time Bucket[14]

  • QuestDB WHERE IN[15]

GreptimeDB 的 RANGE QUERY 是其中最强大的。不过其中 ALIGN / RANGE / FILL 的含义和应该出现的位置需要一点点学习成本,我应该近期会写一篇文章来讨论这个场景的需求和 RANGE QUERY 的实现。

持续聚合

InfluxQL 支持持续聚合[16],这在 SQL 当中是标准的物化视图(Materialized View)的需求,TimescaleDB 就使用了 MATERIALIZED VIEW 的相关语法来实现持续聚合。

不过物化视图在大部分 SQL 数据库中的实现都比较脆弱,目前仍然是一个有待探索的领域。部分时序数据库会实现自己的持续集合方案,例如 GreptimeDB 基于数据流引擎实现了持续聚合。

参考资料

[1]

InfluxQL: https://docs.influxdata.com/influxdb/v1/query_language/

[2]

模型失配导致的额外挑战: https://docs.influxdata.com/influxdb/v2/query-data/influxql/

[3]

Flux: https://docs.influxdata.com/flux/v0/

[4]

弃用: https://docs.influxdata.com/flux/v0/future-of-flux/

[5]

标准 SQL 执行查询: https://docs.greptime.com/user-guide/query-data/sql

[6]

输入行为分析示例: https://github.com/GreptimeTeam/demo-scene/tree/main/keyboard-monitor

[7]

RANGE QUERY: https://docs.greptime.com/user-guide/query-data/sql#aggregate-data-by-time-window

[8]

MySQL: https://docs.greptime.com/user-guide/clients/mysql#time-zone

[9]

PostgreSQL: https://docs.greptime.com/user-guide/clients/postgresql#time-zone

[10]

数据模型: https://docs.greptime.com/user-guide/concepts/data-model

[11]

GreptimeDB JOIN: https://docs.greptime.com/reference/sql/join

[12]

QuestDB: https://questdb.io/docs/reference/sql/join/

[13]

GreptimeDB RANGE QUERY: https://docs.greptime.com/user-guide/query-data/sql#aggregate-data-by-time-window

[14]

TimescaleDB Time Bucket: https://docs.timescale.com/use-timescale/latest/time-buckets/

[15]

QuestDB WHERE IN: https://questdb.io/docs/reference/sql/where/#time-range-where-in

[16]

持续聚合: https://docs.influxdata.com/influxdb/v1/query_language/continuous_queries/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/692726.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

172.二叉树:左叶子之和(力扣)

代码解决 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr, right(nullptr) {}* Tree…

深入理解C语言:main函数的奥秘

在C语言中,main函数是每个程序的入口点,起着至关重要的作用。本文将深入探讨main函数的工作原理,包括其参数、返回值、以及如何从main启动程序的执行。通过实际代码示例,读者将更深入地理解main函数在C语言编程中的核心地位。 第一…

APP单页分发源码下载安卓苹果自动识别apk描述文件免签自动安装

下载地址:APP单页分发源码下载安卓苹果自动识别apk描述文件免签自动安装

Ubuntu虚拟机使用纯命令行对根分区进行扩展

Ubuntu虚拟机使用纯命令行对根分区进行扩展 前排提示 因为Ubuntu再安装时,根分区是没有使用LVM进行磁盘管理的,所以如果想扩展根分区,我们不得不使用另外一种暴力的方法。简单来说就是利用fdisk删除原来的根分区再基于原来的起始块号重新建…

使用C++结合OpenCV进行图像处理与分类

⭐️我叫忆_恒心,一名喜欢书写博客的在读研究生👨‍🎓。 如果觉得本文能帮到您,麻烦点个赞👍呗! 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三…

LabVIEW与PLC的区别

LabVIEW和PLC是工业自动化领域中常见的两种控制和测控方案,各自有独特的优点和适用场景。本文将从多角度比较两者,帮助用户在选择控制系统时做出更明智的决策。 技术背景 LabVIEW LabVIEW是由National Instruments公司开发的图形化编程环境&#xff0…

C# 界面控件中英切换

编程软件:VS 2015 需求:界面有两个按钮,点击可以将界面上所有控件进行不同语言的切换。 一共两种方案,个人认为第二种方案使用范围更广(这里以中英文切换为例)。 方案一:如图所示,建立两个资源文件 将所需控件的中英…

大厂真实面试题(一)

滴滴大数据sql 取出累计值与1000差值最小的记录 1.题目 已知有表t_cost_detail包含id和money两列,id为自增,请累加计算money值,并求出累加值与1000差值最小的记录。 2.分析 本题主要是想找到累加值域1000差距最小的记录,也就是我们要对上述按照id进行排序并且累加,并…

Python 机器学习 基础 之 【实战案例】中药数据分析项目实战

Python 机器学习 基础 之 【实战案例】中药数据分析项目实战 目录 Python 机器学习 基础 之 【实战案例】中药数据分析项目实战 一、简单介绍 二、中药数据分析项目实战 三、数据处理与分析实战 1、数据读取 2、中药材数据集的数据处理与分析 2.1数据清洗 2.2、 提取别…

如何微调 Llama 3 进行序列分类?

节前,我们星球组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂朋友、参加社招和校招面试的同学. 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总合集&…

如何在隔离环境中设置 LocalAI 以实现 GPU 驱动的文本嵌入

作者:来自 Elastic Valeriy Khakhutskyy 你是否想在 Elasticsearch 向量数据库之上构建 RAG 应用程序?你是否需要对大量数据使用语义搜索?你是否需要在隔离环境中本地运行?本文将向你展示如何操作。 Elasticsearch 提供了多种方法…

Python:处理矩阵之NumPy库(上)

目录 1.前言 2.Python中打开文件操作 3.初步认识NumPy库 4.使用NumPy库 5.NumPy库中的维度 6.array函数 7.arange函数 8.linspace函数 9.logspace函数 10.zeros函数 11.eye函数 前言 NumPy库是一个开源的Python科学计算库,它提供了高性能的多维数组对象、派生对…

CSS函数: translate、translate3d的使用

translate()和translate3d()函数可以实现元素在指定轴的平移的功能。函数使用在CSS转换属性transform的属性值。实现转换的函数类型有: translate():2D平面实现X轴、Y轴的平移translate3d():3D空间实现位置的平移translateX():实…

中国现代书法第一人颜廷利:全球知名哲学家思想家教育家

在人生的旅途中,如果一个人的所有追求仅仅是为了满足自己的需求和欲望,而非出于善意、行善或造福他人,那么无论其遭受了多少苦难,这样的生活是难以赢得他人的同情或怜悯的。这是东方哲学家、科学家颜廷利教授在其著作《升命学说》…

GQA,MLA之外的另一种KV Cache压缩方式:动态内存压缩(DMC)

0x0. 前言 在openreview上看到最近NV的一个KV Cache压缩工作:https://openreview.net/pdf?idtDRYrAkOB7 ,感觉思路还是有一些意思的,所以这里就分享一下。 简单来说就是paper提出通过一种特殊的方式continue train一下原始的大模型&#x…

一场决定未来的战役,又是梦想起航的地方

大家好,我是小悟 今天不聊技术也不说系统,2024年高考的第一天,首先祝愿所有高考生在这特别的日子里,心态沉稳,答题顺利,让多年的努力在这一刻绽放光芒。 高考,这个承载了无数青春梦想与汗水的…

【栈】2751. 机器人碰撞

本文涉及知识点 栈 LeetCode2751. 机器人碰撞 现有 n 个机器人,编号从 1 开始,每个机器人包含在路线上的位置、健康度和移动方向。 给你下标从 0 开始的两个整数数组 positions、healths 和一个字符串 directions(directions[i] 为 ‘L’ …

OCP-042之:Oracle结构体系

1. Oracle结构体系 1.1 概述 1.1.1 版本 版本后缀所代表的含义 i:代表基于Internet架构的数据库,如9i g:代表基于grid(网格)的数据库,如11g grid的目的:降低成本,提高服务质量,简化管理 Storage Grid:ASM(automatic storage management),继承了LVM技术,Oracl…

MySQL常用的库操作、表操作、INSERT、DELETE

库操作 查询数据库: show databases; 创建数据库: create database chat; 删除数据库: drop database chat; 选择数据库: use chat; 表操作 查询表: show tables&am…

OpenCompass 大模型评测作业(lesson 7)

书生浦语大模型实战系列文章目录 书生浦语大模型全链路开源体系发展历程和特点(lesson 1) 部署 InternLM2-Chat-1.8B(lesson 2-1) 部署八戒demo InternLM2-Chat-1.8B(lesson 2-2) 部署InternLM2-Chat-7B 模…