Apache IoTDB 树表双模型直播回顾(上)

2 月 26 日面向 Apache IoTDB 树表双模型的功能特性、适用场景、建模选择和未来规划,田原同学通过直播进行了全面解答。以下为直播讲稿(上),干货满满,建议收藏⬇️⬇️

⚡️注意:

  1. 功能演示部分请直接查看视频(1:21:17 开始)观看

  2. 需要获取直播 PPT 请联系小助手欧欧(微信号 apache_iotdb)

时序数据模型介绍(本期文字)

表模型功能介绍

创建表模型连接

数据库&表管理

数据写入

数据删除

数据更新

数据查询

表模型 RoadMap

各位线上的观众朋友大家好,我是田原,是 Apache IoTDB 的 PMC Member,毕业于清华大学软件学院。大家对 IoTDB 比较熟悉的朋友或者同学应该知道 IoTDB 是清华软件学院捐献给 Apache 基金会的,在 Apache 基金会孵化毕业成 Apache 基金会的顶级项目。所以我也是从研究生阶段就一直在做 IoTDB 的相关研究,毕业之后加入了天谋科技,继续全职地去进行 IoTDB 的开发。

IoTDB 在去年一年,或者说其实从前年的年底,已经开始酝酿在做今天要讲的表模型。经过去年一年大家的努力和打磨,表模型也是终于在今年的 2 月份我们发了一个 2.0.1 的 Beta 版本出来。我今天的演讲就是主要去介绍我们表模型的这整个功能,主要分成四个部分。

首先会跟大家简单去介绍一下时序数据模型,其实就是给大家介绍一个背景,包括其中的关键的概念。IoTDB 树模型和表模型之间,大家可能树模型用得会比较多,树模型和表模型分别是什么含义?有什么差别?我们作为用户该怎么去做树模型跟表模型的选择?以及我们在不同场景下面该怎么去建模?这个部分的最后还会跟大家简单介绍一下怎么从 1.x 的版本升级到 2.0 的版本,因为有可能有一些老用户想去升级到 2.0 的版本,去体验一些新的功能,这也是有一些朋友在微信群里面去问的。

第二个部分会仔细跟大家去讲解这一次新增的表模型的使用方式,包括我们的库跟表的管理,还有数据的增删改查。

第三个部分会分享一下我们的规划,就是 IoTDB 表模型在整个 2025 年的功能迭代的时间表,大家也可以参照这个时间表去看自己想要的功能在哪一个阶段会出来。当然这个 Roadmap 不是一成不变的,我们可能在每次版本迭代的过程当中会听取社区同学的一些意见,或者大家更想要的功能,然后去及时地调整我们这个功能的时间线。

最后一个部分会跟大家简单演示一下我们表模型怎么样的实际操作,也就是在我的本机给大家做一个 SQL 的演示。

01

时序数据模型介绍

第一个部分是时序模型的背景介绍。老生常谈:什么是时序数据?其实时序数据有很多种,这里提到的工业大数据里面包含一些时序数据,那我们平时一些机房里面的 APM 数据,也就是服务器的一些监控数据,包括运行程序的一些 tracing 的数据,这些其实都跟时序数据相关。IoTDB 其实着重去解决的是工业大数据这一块,而时序数据就是工业大数据的一种。大家可以看到工业大数据包含哪些?一个是我们的工业信息化的数据,这个里面有结构化的数据,也有非结构化的数据,还有一些产业链的跨界数据。那当然最大的一部分内容就是我们的机器设备数据,也就是刚刚说的这些时序数据。

时序数据也叫时间序列数据,是反映机器设备实时运行状态的监控数据,是我们工业数字化和智能化升级的基础。它这个里面其实涉及到两个比较重要的概念,一个叫设备,一个叫测点,这个也是大家提的会比较多的。设备其实是对应了我们物理世界当中的一个实际场景当中的物理设备,比如我开的一辆车,这个车可能就作为一个设备,或者在一些风电场景里面,那一个风机它可能就是一个设备。

但是风机本身它作为载体,它是不会去采集数据的,真正采集数据的应该是这个风机里边的一个采集点位或者说测点传感器,所以一个设备会通常包含很多个测点,也就是传感器会无时无刻地采集数据,那这个测点就是我们所说的这个设备上面的一个采集点位,能够定期地帮我们去采集环境里面的物理量。采集点位每一个时间点可能去采集一个,多个数据点去按时间戳递增排列形成的就是我们说的一个时间序列。

时间序列的表现形式其实有很多。比如我们可以以表格的形式去把它展示出来,一列是时间戳列,一列是我们的值列。这里举了一个风机的例子,它可能每时每刻去采集自己的发电量,随着时间戳的递增,其实这个值是在无时无刻地去采集的。当然这个没有那么直观,我们可以看到如果用一些可视化的形式,比如我们以横轴为我们的时间轴,纵轴为我们的值轴,那它画出来大家看上去就会更贴切一些。因为如果我们去医院做心电图,这个就很像我们医院机器里面去打印出来的心电图,医生可以通过心电图去看出来我们是不是有一些心脏上面的问题。那同样的,一些专家如果能够看到某一个测点去采集的,我们称为设备的心电图,他也能去判断出来这个设备有没有问题。大家可以看到,比如突出的这个部分,肉眼一看就知道它应该是一个异常点,也叫特殊工况点,那就会针对这部分数据再进行进一步的分析,但这一切可视化的基础其实就基于我们测点所采集的数据需要去存下来,可视化只是存下来数据的一种展现形式。

那我们如何管理刚刚说的这些数据呢?其实就是怎么样把刚刚提到的两个重要概念,就是现实世界当中的设备和测点去映射到我们数据库的一些逻辑概念上面。在 IoTDB 诞生之初,我们是选择了跟工业数采最贴近的测点管理模式,这个也是以 PI 为典型代表的实时数据库、SCADA、DCS 系统的核心数据管理范式。这里面的每一个测点就是指一个独立的监测点位,它对应了一条时间序列。我们在此基础上创新地提出了树形的数据模型,也就是我们常常简称的树模型,也对应去发明了一套以极简的树形数据访问 SQL,当然它不是标准的 SQL,为自动化领域用户的采数跟用数提供了一些直观和便捷的使用方式,因为现实世界当中,很多信息的组织方式都是这种层次结构的。

比如大家看到这个树形结构,第一点可能能想到的是什么?就是我们电脑上的文件系统,对吧?大家应用文件系统比较多,点到一个文件夹里面可能还嵌套着一个文件夹,直到最后叶子节点它有一个文件,所以树形模型的层次化结构可视化之后是很容易被用户所接受的。

在满足工业现场监控场景的需求之后,我们积累了一些用户,所以进一步去研究这些用户对于时序数据分析场景的需求和使用习惯,发现有一些场景需求下面,树模型的极简 SQL 没有办法去覆盖到,所以推出了今天所要讲的主角,也就是表视图,也叫表模型。相应的而言,表模型会有它自己的一套查询语言,是跟标准 SQL 去兼容的,为有数据分析需求的用户去计算和分析时序数据提供了标准,并且能够使用丰富的查询语言。

但是从表结构上面,大家也能看到,跟上面一张图的树形结构相比,它没有办法直观地看出来这个表里面不同列之间层级的包含关系。这张树形图,你能很明显地感觉到集团下面包含了工厂,工厂下面包含了设备,设备下面包含了测点,从上到下是很直观的。但是对于一张表而言,你可能并不能够轻易地看出来,如果我把这个顺序打乱,大家从左往右看,可能能看出来集团>工厂>设备,设备跟测点的关系中间又隔了一个时间列,可能就不是那么直观了。如果我在建表的时候把这个顺序打乱一点,比如把工厂放到前面去,那大家就更看不出来这之间的关系了。在现实世界里面,很多时候数据库的不同列之间确实是有一个隶属关系的。

IoTDB 跟传统的关系型数据库也有一点不一样,IoTDB 这个表模型它是可以不预先去定义我们的表结构的,它可以通过在某些 SDK 接口写入的时候去自动创建我们的表,或者自动扩充我们的列。这是什么意思呢?就是如果是一个关系型数据库,你第一步要做的是什么?要设计你的 schema,设计完了之后,你需要根据你设计出来的 schema 写好你的 create table 语句, create database 先创建好,然后再在这个 database 下面去把 table 创建好。比如这里的集团、工厂、设备、时间、测点 1、测点 2,它都需要在 create table 的语句当中写好,这样我才能对这张表进行写入。如果我写入的时候这张表没有创建好,它会报表不存在的错误。如果我写入的时候,这张表建成这个样子,但是我写入的时候多带了一列,这个列在我建表的时候不存在,那同样的,关系型数据库写入的时候也会报这个列不存在的异常。

但是 IoTDB 它在做表模型的时候考虑到一些工业用户的需求,因为一些设备它可能会更新换代,或者说它的一些测点在业务人员沟通过程中,现场的人员跟后面负责数据采集或者数据存储的人员沟通不是很及时,那就有可能设备增加了一个测点,增加的时候如果数据包上面已经有这个测点了,写入的时候带这个测点写下去,如果报错的话,那这个数据可能就会丢失了,或者说不断重试导致写入阻塞了。所以基于这一点考虑,IoTDB 其实在某一些 SDK 的情况下面是支持了我们写入时的自动建表,包括自动扩充列的这些功能的,这个在后面也会提到,当然也有一些写入接口它是不支持的。

刚刚提到,表模型的查询语言是兼容标准 SQL 的。SQL 是 Structured Query Language,结构化查询语言的一个缩写,维基百科上面给它的定义是一种特定目的的编程语言,用于去管理关系型数据库的管理系统,或是在关系流数据管理系统当中进行流处理。其实这个可以扩展一下,现在的标准 SQL 已经不仅仅是这些,因为后面也会提到 SQL:2023 新增了属性图的查询,所以它也可能利用在图数据库管理系统当中。包括很多时序数据库都想去兼容标准 SQL,只是在标准 SQL 上面扩充了一些时序的查询能力,那其实标准 SQL 也可以说用于管理我们时序数据库管理系统。

SQL 的发展历程我也跟大家简单分享一下,因为这个涉及到大家都说去兼容标准 SQL,是兼容标准 SQL 的哪一个版本,到底哪一个版本的多少功能去实现了?大家都说兼容,但是并没有去讲清楚,所以先把这个 SQL 发展或者 SQL 发版的流程给大家简单讲一下。SQL 其实最早标准化是在 1986 年,是被美国国家标准学会,也就是 ANSI 去标准化的,当时它还是一个美国的标准。一年之后的 1987 年,它是被国际标准化组织 ISO(International Organization for Standardization)标准化了,这个时候就往国际上面去推了。

它第一个为人所熟知,或者说是现代 SQL 的基础的,大家达成共识的应该是 SQL-92,也就是 1992 年去发版的这个 SQL,有时候可能有一些别名,大家会叫 SQL2。1999 年的时候,它扩充了很大一部分功能,比如正则表达式的匹配、触发器、递归查询,也就是 with 这些,以及过程式与控制流语句等等,还有非标量的数据类型这一块。原来大家讲关系型数据库,它的关系代数里面对于某一列可能要求必须是原子类型的,但这会儿它也引入了一些非标量类型,比如像数组,也引入了一些对象特性。大家也可以注意到,从 1999 年开始, SQL 规范的名字也变了,原来是 SQL-92,现在都是变成一个四位的年份了,也是因为千禧年到了,从 1999 年开始后面都是四位的年份。2003 年也是一个比较重要的版本,它新增了很多分析类的查询特性,比如窗口函数,还有表函数。SQL:2006 主要新增了导入导出 XML 数据相关的。2008 年的时候也有一些小的改动,到了 2011 年,它增强了 window function 和 fetch 子句,同时大家也可以注意到它增加了一种时态数据。时态数据英文是叫 temporal data,这块大家可以注意一下,它跟时序数据是两个东西,有时候会被混淆。2016 年的时候它进一步增强了 SQL 的分析能力,增加了行模式匹配 RowPattern Recognition,还有多态表函数、JSON 的支持等等。所以 SQL:2016 也是一个改动比较大的规范。因为 SQL 标准分很多个部分,所以它如果有一些比较大的新增改动,它会增加单独的一个章节去描述它。2019 年的时候增加了第 15 章节,描述了多维数组。2023 年的时候,除了一些小的改动之外,最大的改动就是它增加了第 16 章节去描述属性图的查询,把一些常见的图数据库里面的查询语法怎样用 SQL 表达出来做了一个规范。

那 IoTDB 里的表模型实现了哪些呢?可以说它基本上实现了 SQL-92 里面的大多数功能,我们也在加速实现高版本 SQL 规范中定义的多种特性,去优化我们用户的查询体验。表中画绿色的部分是我们目前已经支持了的,画红色的部分是我们正在支持的,后续版本会真正放出来的,比如窗口函数、表函数、行模式匹配、多态表函数等等。多态表函数跟表函数它其实是一个包含关系,2016 年版本其实相当于在 2003 年的表函数上面增加了一个多态的功能,所以我们 IoTDB 做的时候就直接做成了多态表函数的方式。

简单介绍了一下 SQL 标准以及 IoTDB 它兼容的是哪一个标准,讲完这个,我们有了 IoTDB 的表模型之后,还能带来哪些好处呢?大家以前可能用的是一些关系型数据库,比如 MySQL、PostgreSQL,或者一些键值类的数据库,比如 HBase 等等,这些其实更多对于用户暴露的是一个关系表的模型,它迁移到 IoTDB 树模型的时候,大家会有一个鸿沟,可能不那么容易转过来。包括有用其他一些时序数据库的,像 OpenTSDB、InfluxDB、TimescaleDB 等等,它也是展现表格的模型,之前从这部分数据去迁移到 IoTDB 的时候,可能要涉及到模型的转换。但是现在 IoTDB 有了表模型之后,它里面的很多概念跟其他数据库是一样的,所以大家在做数据迁移的时候会更加方便。

这是外部数据去导入 IoTDB 的过程会更加方便,那 IoTDB 里面的数据被外部数据所集成也会更加无缝,因为现在像 Kafka、Flink、Spark 也都有对应推出来一些自己的 SQL,也是更多的面向表格去做的对外接口设计,所以我们 IoTDB 有了表模型之后,跟这些生态的集成会更加无缝。包括刚刚没有提的 DBeaver,其实是关系型数据库的一个可视化界面。之前树模型跟 DBeaver 不太好做集成,因为 DBeaver 是面向关系型数据库的这样一个设计,所以它的可视化界面你在运用树模型的时候不是那么直观。但有了表模型之后,大家可能就不需要用我们提供的 CLI 命令行去操作,可以直接用 DBeaver 连上去可视化界面,用鼠标点一点就能看到一些信息。

跟大家简单介绍了一下 IoTDB 双模型的背景之后,接下来我会再仔细地去剖析一下 IoTDB 里面的表模型和关系型数据库的表不一样的一些概念。数据库的概念其实跟关系型数据库没有什么太大的区别,它是一个物理数据隔离的这样一个概念,可以管理多类设备。

我们管我们表模型的表叫做一个时序表,因为它有一定的时序语义,它对应了一类设备。之前有同学在群里面问 IoTDB 这一张表到底管几个设备,是不是一个设备要建一张表?不是的,我们是要一类设备去对应一个时序表,也就是说如果这些设备的测点都是一样的,它就可以放到一张表里面,IoTDB 不需要去建很多很多的表,它会把并行化的写入放到 IoTDB 内部去做并行化,所以大家去建的时候只需要建一张表就行了。这个表跟其他关系型数据库如果有不一样的地方,就是我们对于表的列做了一些分类,有不同的类别。第一个类别就是我们的 TIME 列,就是时间列,这个大家很容易理解,因为采集数据的时候肯定会有一个时间。每一个时序表必须要有一个时间列,列名必须为 time,那数据类型为 TIMESTAMP。第二类是我们的标签列 TAG 列,这个是设备的唯一标识,它可以为 0 个,也可以有很多个,为 0 个的特殊场景到后面我在建模场景的时候会跟大家去提。这个 TAG 其实就是唯一标识了,物理世界当中一个设备的标签信息是不可以修改和删除的,但是这个标签列是允许动态增加的,也就是随着 SDK 写入的时候会动态的增加。因为没有树模型层次结构的概念了,所以如果你的隶属关系不是那么直观的话,我们在建模的时候是推荐按粒度的从大到小去排列的。create table 的时候,你先写集团,再写下面的厂区,再写下面的设备。

测点列,就是设备下面的一个个的测点/采集点,一个设备的采集点可以有一个或者多个,它的值是随时间变化的。我们表模型的测点列是没有数量限制的,之前有其他的一些关系型数据库,可能它对于表的列数上限是有限制的,那么 IoTDB 是可以达到数十万以上的。

还会有一个特殊的列,叫属性列,属性列是对设备的一个补充的描述,因为除了设备的唯一标识之外,可能还会有一些静态的属性,这些静态属性也是基本不随时间变换的。比如我的一辆车,车的标识 ID 应该是在车架上面会有一个车架号。而这个车是什么颜色,它出厂的时候确实也确定了,比如这辆车是黑色的,那这个基本上是不随时间变换的,但是如果我去改个膜或者刷个另外颜色的车漆,它也是有可能会改变的。通过一辆车的颜色,你是不可能唯一定位到一辆车的,但是你可以通过一个车的车架号去唯一定位到一个车,这个就是属性跟标签列的一个区别,在后面我也会以一个更加生动的例子去跟大家简单介绍一下。所以我们是希望大家把一些希望修改的、少量的静态属性放到我们的属性列当中,每个设备的静态属性只会存储一次,不会在每一行数据都重复存储,大家是不用担心它磁盘占用的。当然,select 的时候如果我带上了这个属性列,在每一行上面都会展示这个属性列的值,但是这个只是相当于关系型数据库里面的 join 功能,只是在最后数据展示的时候给你拼凑在每一行上面,物理上面它只会存储一次。

数据的筛选效率其实也是有差别的,这是为什么呢?是因为我们 IoTDB 它像关系型数据库一样,也有一个主键的概念。主键就是这一行数据的唯一标识符,它是由所有的标签列加上时间列去组成的,所以如果你 where 条件里面带上了标签列和 TIME 列的索引过滤条件,它的效率是很高的,因为在上面默认建了一些索引。属性列也有一些索引,但是它的过滤效率,比如我要查所有红色的车,那它的过滤效率可能就不如我指定要查我自己的那辆车架号为多少的车快。还有一些测点列上面的过滤条件,比如对于温度的话,正常体温是 37 度,我要查一些异常温度,就是我要查所有我大于 37 度的时候的值,那我就写了一个 temperature > 37。这种查询因为在值列上面我们是没有精确的索引的,所以它的筛选效率可能不会有前面这些标签列、属性列跟时间列高。但是 IoTDB 底层存储的时候,它也是会给这些测点列去记录一些稀疏索引的,所以真正大家去做值过滤的时候,比如温度大于 37,只要它是一个异常数据,也就是它的筛选率很低,是可以通过我们的稀疏索引过滤掉很大一部分数据的,它的效率也不一定有大家想象得那么差。它不会真的是去扫全表的,当然最坏情况可能是它要扫全表,如果你不带时间列的过滤条件的话。

这一页主要想跟大家再强调一下,我们的标签列和属性列的区别是什么,以及我们怎么判断哪些列是标签列,哪些列是属性列。寒假或者过年的时候,哪吒 2 也是出圈了,我这边是以哪吒的身份证号去给大家做一个简单的对于标签列跟属性列区别的判断。一张身份证大家拿到之后,可以看到它里面最有用的是什么?就是我的身份证号,这个身份证号是能够唯一标识一个人的。就像我们的标签列,标签列是唯一对应到一个设备的,通过所有的标签列的值,我们就能唯一准确地定位到一个设备。它写入之后就不可以修改,就跟我们的身份证号是一样的,你从出生拿到出生证明开始,已经生成这个身份证号了,那你的身份证号就不可能变了,它会一直跟随你到老、到去世,即使去世了之后,你的身份证号也不会被其他人复用,所以这是唯一定位一个人的方式,它是你唯一的公民标识,对吧?

那属于人的一些其他属性,比如我们的身份证照片,它是可以随时换的,大家应该感受很深,我换一个身份证,我就能换一张身份证照片,我重新拍一下就行了。名字,很容易理解,很多人有时候嫌自己爸妈取的名字不好听,可能就直接改了,所以名字也是可以改的。性别,当然在中国很难改,但是去泰国其实你的性别也是可以改的。住址,大家也可以去换。籍贯,其实人出生之后就定了,但是有时候我们去填籍贯也有可能填错,大家如果填错了,应该也是可以更正的。出生日期是改不了的,这个出生日期其实算一个冗余信息,因为大家了解身份证号码的构成之后,你会发现中间有一段是你的出生日期年月日,所以它跟身份证号是有一点点重复的,为什么又去把它展示一遍呢?其实就是因为如果从你的身份证号上去看的话,一串数字你还得分析一下中间这一段,之后再取出来这一段去知道出生日期是怎样的,它就不如这样直接展示方便,所以一些信息的冗余存储它是为了方便查询或者方便用户理解的。刚刚我描述的这些有的可变,有的不可变的信息,其实是对我们这个人的补充描述,它是基本上不随时间变化的,但是是可以修改的,如果你想修改的话是可以改的。我们设备的属性列也是一样的,它是对于设备的一个补充描述,也不随时间变化,是可以修改的一些设备的静态属性。

那对于这个人,我们怎么建这个时序表呢?首先我们得选定他的身份证号作为我们的设备 ID,然后姓名、性别、籍贯、住址、照片,因为都可以修改,但是又不随时间变化,所以我就把它们作为属性列。还有一列 TIME 列,最后我采集时序数据的时候是给他身上装个定位器,我能实时地采集他的经纬度坐标,所以经度、纬度就是我们的 FIELD 列,也就是我们的测点列,这样一张时序表就建好了。所以大家通过这个例子也能够理解我们怎么样去区分哪些列作为标签列,哪些列作为属性列。

接下来我会通过三个典型的场景去介绍我们怎么样用树模型在某些场景下建模,怎样用新的表模型在这些场景下建模。第一个场景是有多种类型的设备需要管理的时候,这个多种就是 ≥1,如果只有一种设备类型需要管理,那就很简单了,也是隶属于这个场景的。如果有多种的时候,树模型应该怎么办?我们可以在数据库节点下面按设备的类型去创建分支,每种设备类型下面可以有不同的测点结构。比如下面左下角这张图,我有风机要管理,也有电机要管理,这个时候我就在 DATABASE 下面分别创建了风机跟电机这两个节点,风机节点下面的所有子树去管理风机数据,电机下面的所有子数去管理电机数据。风机采集的时候,可能采集点只有电压跟电流,但电机可能采集的是功率、电量跟温度。这两种类型的设备采集的测点类型是不一样的,所以我们就分成了树的两个分支去建。

那对于表模型来讲,它应该是每一个类型去建一张表,对应到这个例子,就是我们要建一个风机的设备表,建一个电机的设备表,那风机有哪两个 TAG 列或者标识列呢?我一般都是要哪个风机组的哪个风机号,就像我们在学校怎么定位到一个学生,肯定说几排几座就不能定位到他了,你得说几年级几班的几排几座,所以这个风机组下面的某一个风机号才能唯一定位到这一个风机。同理,电机也是一样的,它需要有电机组跟电机号作为这一个设备的唯一标识。当然还有时间列和测点列,对于风机的设备表有电压跟电流这两个测点列,对于电机有电量跟温度。这里没有属性列,因为有的时候可能这个设备也没有什么静态属性需要去存储,所以也不一定非得带上属性列。

第二个场景是没有设备只有测点。比如场站的监控系统里面,每个测点都有唯一的编号,但是没有办法对应到某些设备。对于树模型来讲,我们是允许你直接在 DATABASE 这个节点下面创建测点的,所以你可以直接在 DATABASE 下面把这些测点挨个列下来。而表模型,这个就引出了我刚刚在介绍表模型四类列的时候,我描述说 TAG 列是可以 ≥0 个,也就是说可以没有 TAG 列。所以我们可以建一张表,只有 TIME 列和一堆测点列,每一个测点对应一个测点列,跟树模型也是一样的。测点列的列数是没有上限的,所以你可以随便扩展。

第三个场景是一个设备下面既有子设备也有测点,这个是什么场景呢?比如在储能场景当中,它每一级的层级结构都需要去监控电流和电压。比如电站下面有电池仓,电池仓要监测电流和电压,电池仓下面有更小的粒度叫电池堆,电池堆要监测自己的电流、电压,电池堆下面有电池簇,电池簇下面还有电池芯,它每一个层级都需要去监测电流跟电压,所以就形成了这样一个树形结构。而树模型本身天然地允许设备之间存在这种嵌套关系,因为这个树的孩子节点可以是叶子节点,也可以是中间节点,这个树模型并没有禁止,所以树模型可以去建出来这样一棵树。

那对于表模型,我们其实是推荐多个表进行管理的,也就是我们会把电池仓单独作为一个表,电池堆单独作为一个表,电池簇又单独作为一个设备表,最后是一个电池芯的表,所以这对应了四个表。不同的表标识列是不一样的,比如我要定位一个电池仓,其实我只需要知道它的电池站的号是哪一个站,以及是哪一个仓号。对于电池堆的话,这个仓号还不够,我可能还得知道这个仓号下面你是哪一个电池堆的。那每一级它都会多一个标识列,所以建出来的四张表每张表的标签列还不一样。

当然也有其他的建模方式,比如因为它们下面的测点其实是一样的,我也可以直接用下面的这个表去表征,但是这样不好在哪里,就是我如果要去查电池仓 1 下面的电压跟电流的话,我在 where 条件里面要多写一些。因为它其实是没有电池堆、电池簇跟电池芯的号的,我需要在 where 里面写电池堆 is null,电池簇 is null,电芯 is null,这样其实是比较麻烦的,不如建四张表来得直观。

跟大家简单介绍了一下怎么建模,以及树模型跟表模型各自的功能特点,那就来对比一下它们在功能上面有哪些差异。我们过去一年时间其实都是在开发或者补齐表模型跟树模型的功能差异点,因为树模型的功能表模型也应该能够支持,可能不是完全一样的支持,但是至少是逻辑上面等价的支持。现在,基本的功能、读写功能已经对齐了,有一些还没有支持,是在后续的迭代过程当中。比如一些其他语言的接口,C++、Go 等等;还有树模型里面的 UDF,或者函数质量库,这个目前也还没支持;还有一些特色的分段方式,比如 group by session、 group by variation;还有 lambda 表达式;包括用户和权限管理、数据订阅等等。

今天还有一个用户在群里面去问,我们的表模型能不能上生产?其实我觉得是可以的,因为 IoTDB 的 2.0.1-beta,它是一个 beta 版本, beta 版本迭代的时候只会去修复一些测试过程中大家反馈的 bug。但是它的这些修改是保证向之前的版本兼容的,所以大家去上生产是没有后面的版本跟前面的版本不兼容这样一说,它也是一个稳定版本。但唯一的缺点可能在于哪呢?就是目前这个 beta 版本还没有用户管理和权限管理,所以如果你是部署在一个内网环境,只有你自己能访问到这个数据库,直接用 root 不需要去关心这些权限,那就可以上生产。如果大家是有权限和用户管理的需求的话,可以等下一个 2.0.2 版本,这个时候会把权限和用户管理也做完。

刚刚也说了,表模型在分析能力上因为是完全兼容标准 SQL 的,所以它在一些复杂的查询上其实是要优于树模型的,并且它因为与标准关系 SQL 兼容,一些从关系型数据库迁过来的用户,他的学习成本是比较低的。之前他可能还要花时间去看我们的官网,去学习一下树模型的语法,当然树模型的语法也很简单,但是他毕竟要多这么一步,现在他就可以直接把他之前的一些知识拿过来用了。

跟树模型对比一下,比如 join,表模型其实支持得更加丰富,后面我会提到;子查询,之前树模型是不支持的,表模型是支持关联子查询和非关联子查询的;group by 之前支持得比较有限,比如 group by time、 group by variation 这些,但现在我们定义的 group by 就是标准关系 SQL 定义的 group by,它支持任意的表达式;fill 也是同样的,它原来只能针对整个结果集进行填充,现在我们是能够通过 fill 子句的一些参数实现分组内填充,并且也可以指定实现其他 timestamp 类型的列为辅助列,这一块在后续的功能讲解里面我会跟大家以例子去讲解;还有 distinct,树模型里面不支持 distinct 做去重,表模型也是支持的。表函数和窗口函数,这里表函数是指多态表函数,窗口函数是 SQL:2003 提出来的,多态表函数是 SQL:2016 提出来的,这些树模型还都没有办法支持,但表模型已经在做了,在后续的版本里面也会给大家释放出来。有了这些函数和功能之后,大家做分析类型的查询,可能就不需要在业务端做二次开发了,直接一条 SQL 就能搞定。

这里讲一下树模型和表模型的性能差异。理论上来讲,两者优化到最后性能应该是相同的,只是现阶段由于开发的优先级问题,有一些查询场景树和表会各占优,但这个并非是技术上不能解决的,而是技术上可以解决的。我们的写入性能基本上树表是持平的。简单查询目前是树模型更优,但这个不是不可以解决的,只是因为现阶段表模型的查询语法更复杂,我们也引入了更多的优化规则,导致查询规划阶段的耗时增加,其实执行阶段耗时还是类似的,只是规划阶段耗时增加了一部分。这个也只是在一些简单查询场景下面你能感知出来,因为整体上也就慢了大概 5 毫秒左右,5 毫秒对于一些简单查询可能占比较大,但对于一些复杂查询,本身要查几万行或者几十万行的,它的耗时其实增加并不明显,并且后期我们也可以通过 query plan cache 去复用物理执行计划做加速,但这个正在做,所以在后续的版本里面才会有。复杂的单序列长查询在规划阶段慢一点点,其实在整个阶段里面占比不是很高,耗时基本上是持平的。对于一些复杂类的查询,比如多设备的分析型查询,表是要比树快的。

讲了这么多,其实大家比较关心我到底应该去用树模型,还是应该去用表模型。这边以表格对比的方式,从适用场景、典型操作等多个维度对树模型和表模型做了一个总结性的对比,大家可以根据自己的具体使用需求去选择合适的模型,从而实现高效的数据存储和管理。比如我们的树形模型,它采用了层级结构,能够比较直观地映射物理设备的层级关系,也非常方便地支持了异构设备和独立测点的数据采集管理,和文件系统一样灵活,也可以自己去设计不同的分支结构。它适用于 DCS、 SCADA 等等的工业监控场景。

表模型是以设备为管理单位的,适合大规模设备的数据管理和多属性的关联分析,因为它的分析能力是要强于树模型的,所以能够高效地支撑复杂的批量查询需求。并且它的语法是兼容标准 SQL 的,如果你原来是从关系型数据库迁过来的,那你其实可以直接用表模型了,就不需要去研究树模型了,但是如果你原来是 OT 领域,本来就是工业监控场景的,那你用树模型现有的查询能力也能满足你,对吧?可以直接用我们的树模型就行了,因为它有一些 SQL 写出来确实是比标准 SQL 要简单很多的,所以是各有优劣。

我们现在的集群里面,大家去布 2.0.1-beta 的时候,它是可以同时存在两种模型空间的,不是说我部署了这个实例只能是表,要用树的话必须切到另外一个实例。只是不同模型的数据库命名方式是不同的,比如在树模型下面,它的数据库命名必须是以 root. 开头的,比如 root.db。那表模型里面是没有这个限制的,你可以随意命名,但是不能以 root. 开头。所以这样的方式就能够隔离开来,比如我在树模型里面命名为 root.db,在表模型里面命名为 db,那这是两个不同的数据库,是互相不可见的,我用树的语法连接上去,只能看到 root.db,用表的语法连接上去,只能看到 db。

两个空间的数据,大家可能会担心形成所谓的数据孤岛,但是 IoTDB 是没有这个后顾之忧的,为什么呢?其实 IoTDB 本身无论是树模型还是表模型,我们应该更正一下这个说法,应该是树视图或者表视图,也就是说它底层其实是共享一份存储格式的。IoTDB 存的是什么?它物理上面的模型只是一个时序模型,时序模型里面有什么?最开始给大家介绍过了,设备跟测点,所以在我们物理的 TsFile 文件格式里面,它会看到我们的设备跟测点。至于这个设备和测点你是需要用表格的形式去展现出来,还是以树的形式展现给用户,它只是同一份数据的不同视图。

正好也插播一下,为了支持表视图,我们对底层的 TsFile 文件格式也做了一些改动,TsFile 也升级到 2.0 了。TsFile 作为 Apache 的顶级项目,它是一个独立的项目,是可以单独地提供 TsFile 读写的,你可以像 CSV 或者 Excel 表格一样去读写 TsFile,可以用 TsFile 文件层的 API 去做,大家也可以试一试 TsFile 2.0 的 API。

回到表视图跟树视图来讲,也就是说如果存在一个场景,树模型的一些存量用户升级到 2.0 之后,他的部分场景没有办法用树模型的查询语言直接去实现,比如一些复杂的分析类型查询,他还需要用表视图,那该怎么办?有一种方式就是我建两个 IoTDB 或者说两个 DATABASE,然后我从这个 IoTDB 里面把树模型原来的数据读出来之后,去迁移到表模型,把原来树的方式转成用表建模,再把数据重新倒腾一遍。这种方式好处是什么呢?就是你以后看到的是一个统一的视图,只有表了,后续也可以直接对这个表进行任意的操作了,写也可以用新的语法去写。但是这样就会有数据搬迁的困扰,并且你上层的业务系统得全部重写一遍,原来用树的 SQL 去写的,现在也得用表的 SQL 再写一遍。

IoTDB 并不需要这样,我们得益于底层存储的格式是相同的,树跟表作为两种视图是可以对同一份数据进行操作的,所以我们在进行少量的人工手动介入之后,是可以把原来树视图创建出来的数据去 create 一个 tableview 出来,用一个表视图展现,就是右边这个方式。如果你原来是上面的这种树模型建模方式,我通过 create tableview 语法把它展示成表视图,在表空间里面有这么一个视图,但它的数据其实用的是树视图里面写下来的这个数据。这样的话,原来用户的树模型、用户所有的写入代码、原有的一些简单的查询代码,其实都是不用改的,已存在的业务都不用改,只是新增了一些查询场景,这些业务它可以通过表视图用表的语法去查。这个还是一个比较有意思的功能,最大的收益点就是用户可以同一份数据用两种视图去查,哪一种视图对你更优,你就去选择哪一种视图。这个目前还在开发当中,在后续的版本会释放出来。

还有一个概念跟大家强调一下,就是 IoTDB 并不是一个多模数据库。多模数据库是什么概念?它是一种新型的数据库管理系统,能够支持多种模型,这个模型就是不同类型的数据结构,比如说文档数据库、键值数据库、KV 数据库比如 Redis,图形数据库比如 Neo4j,时序数据库比如 IoTDB,关系型数据库 比如 MySQL,PostgreSQL 等等,这些是它的模型。那 IoTDB 其实刚刚也说了应该纠正一下,叫树视图和表视图,只是大家基本上会把这两个概念混起来,就叫树模型跟表模型了。它底层都是同一种数据结构,也就是时序数据,它只是两种视图、两种语法。这个后面也会介绍,我们去区分表语法跟树语法的时候,它其实是通过 sql_dialect,也就是 SQL 方言的方式去指定的。从这边也可以看出来,IoTDB 并不是一个多模数据库,或者我们并没有去扩展系统边界,想去做一个多模数据库。

这个也是用户群里面大家比较关心的问题,我们怎么去升级?这里我把所有的 IoTDB 版本都列出来了,之前我们在 0.X 的版本去升级到 1.X 的时候,它确实是做了 breaking changes,是没有办法直接升上来的,是需要 load 数据去做这个事。但是从 1.X 版本之后,你是可以直接去升到 2.0 的,只是 1.3 版本可以直接停机升级到 2.0,但是比如我现在正在用 1.2,那是不能够直接升级到 2.0 的,需要先升级到 1.3 版本,再升级到 2.0 的版本,不能跨中间版本去进行升级。而且这个升级是需要停机升级的,因为次版本可能有一些 RPC 的变动,滚动升级的话可能会出现一些问题,但是挨个的小版本内是可以滚动升级的,比如从 2.0.1 直接升级到我们正在开发的 2.0.2 是可以滚动升级的,包括 1.3 系列的版本也是一样的。

未完待续......

欢迎点击阅读原文下载 IoTDB 2.0.1-beta 版本试用!

规上企业应用实例

能源电力: 中核武汉国网信通产业集团华润电力大唐先一上海电气国轩清安储能某储能厂商太极股份

航天航空: 中航机载共性北邮一号卫星

钢铁、金属冶炼: 宝武钢铁中冶赛迪中国恩菲

交通运输: 中车四方长安汽车城建智控德国铁路

智慧工厂与物联: PCB 龙头企业博世力士乐德国宝马北斗智慧物联京东昆仑数据怡养科技绍兴安瑞思

相关推荐
yuren_xia9 小时前
javaweb文件上传:@MultipartConfig注解与Apache Commons FileUpload对比
java·tomcat·apache
伶星3711 小时前
最好Wordpree+Apache+PHP安装教程
开发语言·php·apache
芜丶湖18 小时前
Vulhub靶机 Apache APISIX Dashboard RCE(CVE-2021-45232)(渗透测试详解)
linux·服务器·网络·web安全·apache·安全性测试
_tison21 小时前
夜天之书 #106 Apache 软件基金会如何投票选举?
apache
CRMEB系统商城1 天前
小程序类目调整汇总公告
java·开发语言·小程序·html·php·apache
东方巴黎~Sunsiny2 天前
FastExcel vs EasyExcel vs Apache POI:三者的全面对比分析
java·开发语言·python·apache
abstract学习2 天前
zookeeper
linux·zookeeper·apache
zfyljx2 天前
小程序画带圆角的圆形进度条
java·小程序·apache
城主科技3 天前
【HCIE实验1】模拟 DHCPv6 服务器及 PD 服务器分配 IPv6 地址和前缀的网络环境。
服务器·网络·apache