首頁
>
資源
>
會議活動

Apache IoTDB 樹表雙模型功能詳解:直播回顧(上)

2 月 26 日面向 Apache IoTDB 樹表雙模型的功能特性、適用場景、建模選擇和未來規,田原同學通過直播進行了全面解答。以下為直播講稿(上),干貨滿滿,建議收藏????

各位線上的觀眾朋友大家好,我是田原,是 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 其實著重去解決的是工業大數據這一塊,而時序數據就是工業大數據的一種。大家可以看到工業大數據包含哪些?一個是我們的工業信息化的數據,這個里面有結構化的數據,也有非結構化的數據,還有一些產業鏈的跨界數據。那當然最大的一部分內容就是我們的機器設備數據,也就是剛剛說的這些時序數據。

表模型直播回顧圖1-20240303.png

時序數據也叫時間序列數據,是反映機器設備實時運行狀態的監控數據,是我們工業數字化和智能化升級的基礎。它這個里面其實涉及到兩個比較重要的概念,一個叫設備,一個叫測點,這個也是大家提的會比較多的。設備其實是對應了我們物理世界當中的一個實際場景當中的物理設備,比如我開的一輛車,這個車可能就作為一個設備,或者在一些風電場景里面,那一個風機它可能就是一個設備。

但是風機本身它作為載體,它是不會去采集數據的,真正采集數據的應該是這個風機里邊的一個采集點位或者說測點傳感器,所以一個設備會通常包含很多個測點,也就是傳感器會無時無刻地采集數據,那這個測點就是我們所說的這個設備上面的一個采集點位,能夠定期地幫我們去采集環境里面的物理量。采集點位每一個時間點可能去采集一個,多個數據點去按時間戳遞增排列形成的就是我們說的一個時間序列。

時間序列的表現形式其實有很多。比如我們可以以表格的形式去把它展示出來,一列是時間戳列,一列是我們的值列。這里舉了一個風機的例子,它可能每時每刻去采集自己的發電量,隨著時間戳的遞增,其實這個值是在無時無刻地去采集的。當然這個沒有那么直觀,我們可以看到如果用一些可視化的形式,比如我們以橫軸為我們的時間軸,縱軸為我們的值軸,那它畫出來大家看上去就會更貼切一些。因為如果我們去醫院做心電圖,這個就很像我們醫院機器里面去打印出來的心電圖,醫生可以通過心電圖去看出來我們是不是有一些心臟上面的問題。那同樣的,一些專家如果能夠看到某一個測點去采集的,我們稱為設備的心電圖,他也能去判斷出來這個設備有沒有問題。大家可以看到,比如突出的這個部分,肉眼一看就知道它應該是一個異常點,也叫特殊工況點,那就會針對這部分數據再進行進一步的分析,但這一切可視化的基礎其實就基于我們測點所采集的數據需要去存下來,可視化只是存下來數據的一種展現形式。

表模型直播回顧圖2-20240303.png

那我們如何管理剛剛說的這些數據呢?其實就是怎么樣把剛剛提到的兩個重要概念,就是現實世界當中的設備和測點去映射到我們數據庫的一些邏輯概念上面。在 IoTDB 誕生之初,我們是選擇了跟工業數采最貼近的測點管理模式,這個也是以 PI 為典型代表的實時數據庫、SCADA、DCS 系統的核心數據管理范式。這里面的每一個測點就是指一個獨立的監測點位,它對應了一條時間序列。我們在此基礎上創新地提出了樹形的數據模型,也就是我們常常簡稱的樹模型,也對應去發明了一套以極簡的樹形數據訪問 SQL,當然它不是標準的 SQL,為自動化領域用戶的采數跟用數提供了一些直觀和便捷的使用方式,因為現實世界當中,很多信息的組織方式都是這種層次結構的。

比如大家看到這個樹形結構,第一點可能能想到的是什么?就是我們電腦上的文件系統,對吧?大家應用文件系統比較多,點到一個文件夾里面可能還嵌套著一個文件夾,直到最后葉子節點它有一個文件,所以樹形模型的層次化結構可視化之后是很容易被用戶所接受的。

表模型直播回顧圖3-20240303.png

在滿足工業現場監控場景的需求之后,我們積累了一些用戶,所以進一步去研究這些用戶對于時序數據分析場景的需求和使用習慣,發現有一些場景需求下面,樹模型的極簡 SQL 沒有辦法去覆蓋到,所以推出了今天所要講的主角,也就是表視圖,也叫表模型。相應的而言,表模型會有它自己的一套查詢語言,是跟標準 SQL 去兼容的,為有數據分析需求的用戶去計算和分析時序數據提供了標準,并且能夠使用豐富的查詢語言。

但是從表結構上面,大家也能看到,跟上面一張圖的樹形結構相比,它沒有辦法直觀地看出來這個表里面不同列之間層級的包含關系。這張樹形圖,你能很明顯地感覺到集團下面包含了工廠,工廠下面包含了設備,設備下面包含了測點,從上到下是很直觀的。但是對于一張表而言,你可能并不能夠輕易地看出來,如果我把這個順序打亂,大家從左往右看,可能能看出來集團>工廠>設備,設備跟測點的關系中間又隔了一個時間列,可能就不是那么直觀了。如果我在建表的時候把這個順序打亂一點,比如把工廠放到前面去,那大家就更看不出來這之間的關系了。在現實世界里面,很多時候數據庫的不同列之間確實是有一個隸屬關系的。

IoTDB 跟傳統的關系型數據庫也有一點不一樣,IoTDB 這個表模型它是可以不預先去定義我們的表結構的,它可以通過在某些 SDK 接口寫入的時候去自動創建我們的表,或者自動擴充我們的列。這是什么意思呢?就是如果是一個關系型數據庫,你第一步要做的是什么?要設計你的 schema,設計完了之后,你需要根據你設計出來的 schema 寫好你的 create table 語句, create database 先創建好,然后再在這個 database 下面去把 table 創建好。比如這里的集團、工廠、設備、時間、測點 1、測點 2,它都需要在 create table 的語句當中寫好,這樣我才能對這張表進行寫入。如果我寫入的時候這張表沒有創建好,它會報表不存在的錯誤。如果我寫入的時候,這張表建成這個樣子,但是我寫入的時候多帶了一列,這個列在我建表的時候不存在,那同樣的,關系型數據庫寫入的時候也會報這個列不存在的異常。

但是 IoTDB 它在做表模型的時候考慮到一些工業用戶的需求,因為一些設備它可能會更新換代,或者說它的一些測點在業務人員溝通過程中,現場的人員跟后面負責數據采集或者數據存儲的人員溝通不是很及時,那就有可能設備增加了一個測點,增加的時候如果數據包上面已經有這個測點了,寫入的時候帶這個測點寫下去,如果報錯的話,那這個數據可能就會丟失了,或者說不斷重試導致寫入阻塞了。所以基于這一點考慮,IoTDB 其實在某一些 SDK 的情況下面是支持了我們寫入時的自動建表,包括自動擴充列的這些功能的,這個在后面也會提到,當然也有一些寫入接口它是不支持的。

表模型直播回顧圖4-20240303.png

剛剛提到,表模型的查詢語言是兼容標準 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 做的時候就直接做成了多態表函數的方式。

表模型直播回顧圖5-20240303.png

簡單介紹了一下 SQL 標準以及 IoTDB 它兼容的是哪一個標準,講完這個,我們有了 IoTDB 的表模型之后,還能帶來哪些好處呢?大家以前可能用的是一些關系型數據庫,比如 MySQL、PostgreSQL,或者一些鍵值類的數據庫,比如 HBase 等等,這些其實更多對于用戶暴露的是一個關系表的模型,它遷移到 IoTDB 樹模型的時候,大家會有一個鴻溝,可能不那么容易轉過來。包括有用其他一些時序數據庫的,像 OpenTSDB、InfluxDB、TimescaleDB 等等,它也是展現表格的模型,之前從這部分數據去遷移到 IoTDB 的時候,可能要涉及到模型的轉換。但是現在 IoTDB 有了表模型之后,它里面的很多概念跟其他數據庫是一樣的,所以大家在做數據遷移的時候會更加方便。

這是外部數據去導入 IoTDB 的過程會更加方便,那 IoTDB 里面的數據被外部數據所集成也會更加無縫,因為現在像 Kafka、Flink、Spark 也都有對應推出來一些自己的 SQL,也是更多的面向表格去做的對外接口設計,所以我們 IoTDB 有了表模型之后,跟這些生態的集成會更加無縫。包括剛剛沒有提的 DBeaver,其實是關系型數據庫的一個可視化界面。之前樹模型跟 DBeaver 不太好做集成,因為 DBeaver 是面向關系型數據庫的這樣一個設計,所以它的可視化界面你在運用樹模型的時候不是那么直觀。但有了表模型之后,大家可能就不需要用我們提供的 CLI 命令行去操作,可以直接用 DBeaver 連上去可視化界面,用鼠標點一點就能看到一些信息。

表模型直播回顧圖6-20240303.png

跟大家簡單介紹了一下 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,只要它是一個異常數據,也就是它的篩選率很低,是可以通過我們的稀疏索引過濾掉很大一部分數據的,它的效率也不一定有大家想象得那么差。它不會真的是去掃全表的,當然最壞情況可能是它要掃全表,如果你不帶時間列的過濾條件的話。

表模型直播回顧圖7-20240303.png

這一頁主要想跟大家再強調一下,我們的標簽列和屬性列的區別是什么,以及我們怎么判斷哪些列是標簽列,哪些列是屬性列。寒假或者過年的時候,哪吒 2 也是出圈了,我這邊是以哪吒的身份證號去給大家做一個簡單的對于標簽列跟屬性列區別的判斷。一張身份證大家拿到之后,可以看到它里面最有用的是什么?就是我的身份證號,這個身份證號是能夠唯一標識一個人的。就像我們的標簽列,標簽列是唯一對應到一個設備的,通過所有的標簽列的值,我們就能唯一準確地定位到一個設備。它寫入之后就不可以修改,就跟我們的身份證號是一樣的,你從出生拿到出生證明開始,已經生成這個身份證號了,那你的身份證號就不可能變了,它會一直跟隨你到老、到去世,即使去世了之后,你的身份證號也不會被其他人復用,所以這是唯一定位一個人的方式,它是你唯一的公民標識,對吧?

那屬于人的一些其他屬性,比如我們的身份證照片,它是可以隨時換的,大家應該感受很深,我換一個身份證,我就能換一張身份證照片,我重新拍一下就行了。名字,很容易理解,很多人有時候嫌自己爸媽取的名字不好聽,可能就直接改了,所以名字也是可以改的。性別,當然在中國很難改,但是去泰國其實你的性別也是可以改的。住址,大家也可以去換。籍貫,其實人出生之后就定了,但是有時候我們去填籍貫也有可能填錯,大家如果填錯了,應該也是可以更正的。出生日期是改不了的,這個出生日期其實算一個冗余信息,因為大家了解身份證號碼的構成之后,你會發現中間有一段是你的出生日期年月日,所以它跟身份證號是有一點點重復的,為什么又去把它展示一遍呢?其實就是因為如果從你的身份證號上去看的話,一串數字你還得分析一下中間這一段,之后再取出來這一段去知道出生日期是怎樣的,它就不如這樣直接展示方便,所以一些信息的冗余存儲它是為了方便查詢或者方便用戶理解的。剛剛我描述的這些有的可變,有的不可變的信息,其實是對我們這個人的補充描述,它是基本上不隨時間變化的,但是是可以修改的,如果你想修改的話是可以改的。我們設備的屬性列也是一樣的,它是對于設備的一個補充描述,也不隨時間變化,是可以修改的一些設備的靜態屬性。

那對于這個人,我們怎么建這個時序表呢?首先我們得選定他的身份證號作為我們的設備 ID,然后姓名、性別、籍貫、住址、照片,因為都可以修改,但是又不隨時間變化,所以我就把它們作為屬性列。還有一列 TIME 列,最后我采集時序數據的時候是給他身上裝個定位器,我能實時地采集他的經緯度坐標,所以經度、緯度就是我們的 FIELD 列,也就是我們的測點列,這樣一張時序表就建好了。所以大家通過這個例子也能夠理解我們怎么樣去區分哪些列作為標簽列,哪些列作為屬性列。

表模型直播回顧圖8-20240303.png

接下來我會通過三個典型的場景去介紹我們怎么樣用樹模型在某些場景下建模,怎樣用新的表模型在這些場景下建模。第一個場景是有多種類型的設備需要管理的時候,這個多種就是 ≥1,如果只有一種設備類型需要管理,那就很簡單了,也是隸屬于這個場景的。如果有多種的時候,樹模型應該怎么辦?我們可以在數據庫節點下面按設備的類型去創建分支,每種設備類型下面可以有不同的測點結構。比如下面左下角這張圖,我有風機要管理,也有電機要管理,這個時候我就在 DATABASE 下面分別創建了風機跟電機這兩個節點,風機節點下面的所有子樹去管理風機數據,電機下面的所有子數去管理電機數據。風機采集的時候,可能采集點只有電壓跟電流,但電機可能采集的是功率、電量跟溫度。這兩種類型的設備采集的測點類型是不一樣的,所以我們就分成了樹的兩個分支去建。

那對于表模型來講,它應該是每一個類型去建一張表,對應到這個例子,就是我們要建一個風機的設備表,建一個電機的設備表,那風機有哪兩個 TAG 列或者標識列呢?我一般都是要哪個風機組的哪個風機號,就像我們在學校怎么定位到一個學生,肯定說幾排幾座就不能定位到他了,你得說幾年級幾班的幾排幾座,所以這個風機組下面的某一個風機號才能唯一定位到這一個風機。同理,電機也是一樣的,它需要有電機組跟電機號作為這一個設備的唯一標識。當然還有時間列和測點列,對于風機的設備表有電壓跟電流這兩個測點列,對于電機有電量跟溫度。這里沒有屬性列,因為有的時候可能這個設備也沒有什么靜態屬性需要去存儲,所以也不一定非得帶上屬性列。

表模型直播回顧圖9-20240303.png

第二個場景是沒有設備只有測點。比如場站的監控系統里面,每個測點都有唯一的編號,但是沒有辦法對應到某些設備。對于樹模型來講,我們是允許你直接在 DATABASE 這個節點下面創建測點的,所以你可以直接在 DATABASE 下面把這些測點挨個列下來。而表模型,這個就引出了我剛剛在介紹表模型四類列的時候,我描述說 TAG 列是可以 ≥0 個,也就是說可以沒有 TAG 列。所以我們可以建一張表,只有 TIME 列和一堆測點列,每一個測點對應一個測點列,跟樹模型也是一樣的。測點列的列數是沒有上限的,所以你可以隨便擴展。

表模型直播回顧圖10-20240303.png

第三個場景是一個設備下面既有子設備也有測點,這個是什么場景呢?比如在儲能場景當中,它每一級的層級結構都需要去監控電流和電壓。比如電站下面有電池倉,電池倉要監測電流和電壓,電池倉下面有更小的粒度叫電池堆,電池堆要監測自己的電流、電壓,電池堆下面有電池簇,電池簇下面還有電池芯,它每一個層級都需要去監測電流跟電壓,所以就形成了這樣一個樹形結構。而樹模型本身天然地允許設備之間存在這種嵌套關系,因為這個樹的孩子節點可以是葉子節點,也可以是中間節點,這個樹模型并沒有禁止,所以樹模型可以去建出來這樣一棵樹。

那對于表模型,我們其實是推薦多個表進行管理的,也就是我們會把電池倉單獨作為一個表,電池堆單獨作為一個表,電池簇又單獨作為一個設備表,最后是一個電池芯的表,所以這對應了四個表。不同的表標識列是不一樣的,比如我要定位一個電池倉,其實我只需要知道它的電池站的號是哪一個站,以及是哪一個倉號。對于電池堆的話,這個倉號還不夠,我可能還得知道這個倉號下面你是哪一個電池堆的。那每一級它都會多一個標識列,所以建出來的四張表每張表的標簽列還不一樣。

當然也有其他的建模方式,比如因為它們下面的測點其實是一樣的,我也可以直接用下面的這個表去表征,但是這樣不好在哪里,就是我如果要去查電池倉 1 下面的電壓跟電流的話,我在 where 條件里面要多寫一些。因為它其實是沒有電池堆、電池簇跟電池芯的號的,我需要在 where 里面寫電池堆 is null,電池簇 is null,電芯 is null,這樣其實是比較麻煩的,不如建四張表來得直觀。

表模型直播回顧圖11-20240303.png

跟大家簡單介紹了一下怎么建模,以及樹模型跟表模型各自的功能特點,那就來對比一下它們在功能上面有哪些差異。我們過去一年時間其實都是在開發或者補齊表模型跟樹模型的功能差異點,因為樹模型的功能表模型也應該能夠支持,可能不是完全一樣的支持,但是至少是邏輯上面等價的支持。現在,基本的功能、讀寫功能已經對齊了,有一些還沒有支持,是在后續的迭代過程當中。比如一些其他語言的接口,C++、Go 等等;還有樹模型里面的 UDF,或者函數質量庫,這個目前也還沒支持;還有一些特色的分段方式,比如 group by session、 group by variation;還有 lambda 表達式;包括用戶和權限管理、數據訂閱等等。

今天還有一個用戶在群里面去問,我們的表模型能不能上生產?其實我覺得是可以的,因為 IoTDB 的 2.0.1-beta,它是一個 beta 版本, beta 版本迭代的時候只會去修復一些測試過程中大家反饋的 bug。但是它的這些修改是保證向之前的版本兼容的,所以大家去上生產是沒有后面的版本跟前面的版本不兼容這樣一說,它也是一個穩定版本。但唯一的缺點可能在于哪呢?就是目前這個 beta 版本還沒有用戶管理和權限管理,所以如果你是部署在一個內網環境,只有你自己能訪問到這個數據庫,直接用 root 不需要去關心這些權限,那就可以上生產。如果大家是有權限和用戶管理的需求的話,可以等下一個 2.0.2 版本,這個時候會把權限和用戶管理也做完。

表模型直播回顧圖12-20240303.png

剛剛也說了,表模型在分析能力上因為是完全兼容標準 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 就能搞定。

表模型直播回顧圖13-20240303.png

這里講一下樹模型和表模型的性能差異。理論上來講,兩者優化到最后性能應該是相同的,只是現階段由于開發的優先級問題,有一些查詢場景樹和表會各占優,但這個并非是技術上不能解決的,而是技術上可以解決的。我們的寫入性能基本上樹表是持平的。簡單查詢目前是樹模型更優,但這個不是不可以解決的,只是因為現階段表模型的查詢語法更復雜,我們也引入了更多的優化規則,導致查詢規劃階段的耗時增加,其實執行階段耗時還是類似的,只是規劃階段耗時增加了一部分。這個也只是在一些簡單查詢場景下面你能感知出來,因為整體上也就慢了大概 5 毫秒左右,5 毫秒對于一些簡單查詢可能占比較大,但對于一些復雜查詢,本身要查幾萬行或者幾十萬行的,它的耗時其實增加并不明顯,并且后期我們也可以通過 query plan cache 去復用物理執行計劃做加速,但這個正在做,所以在后續的版本里面才會有。復雜的單序列長查詢在規劃階段慢一點點,其實在整個階段里面占比不是很高,耗時基本上是持平的。對于一些復雜類的查詢,比如多設備的分析型查詢,表是要比樹快的。

表模型直播回顧圖14-20240303.png

講了這么多,其實大家比較關心我到底應該去用樹模型,還是應該去用表模型。這邊以表格對比的方式,從適用場景、典型操作等多個維度對樹模型和表模型做了一個總結性的對比,大家可以根據自己的具體使用需求去選擇合適的模型,從而實現高效的數據存儲和管理。比如我們的樹形模型,它采用了層級結構,能夠比較直觀地映射物理設備的層級關系,也非常方便地支持了異構設備和獨立測點的數據采集管理,和文件系統一樣靈活,也可以自己去設計不同的分支結構。它適用于 DCS、 SCADA 等等的工業監控場景。

表模型是以設備為管理單位的,適合大規模設備的數據管理和多屬性的關聯分析,因為它的分析能力是要強于樹模型的,所以能夠高效地支撐復雜的批量查詢需求。并且它的語法是兼容標準 SQL 的,如果你原來是從關系型數據庫遷過來的,那你其實可以直接用表模型了,就不需要去研究樹模型了,但是如果你原來是 OT 領域,本來就是工業監控場景的,那你用樹模型現有的查詢能力也能滿足你,對吧?可以直接用我們的樹模型就行了,因為它有一些 SQL 寫出來確實是比標準 SQL 要簡單很多的,所以是各有優劣。

我們現在的集群里面,大家去布 2.0.1-beta 的時候,它是可以同時存在兩種模型空間的,不是說我部署了這個實例只能是表,要用樹的話必須切到另外一個實例。只是不同模型的數據庫命名方式是不同的,比如在樹模型下面,它的數據庫命名必須是以 root. 開頭的,比如 root.db。那表模型里面是沒有這個限制的,你可以隨意命名,但是不能以 root. 開頭。所以這樣的方式就能夠隔離開來,比如我在樹模型里面命名為 root.db,在表模型里面命名為 db,那這是兩個不同的數據庫,是互相不可見的,我用樹的語法連接上去,只能看到 root.db,用表的語法連接上去,只能看到 db。

表模型直播回顧圖15-20240303.png

兩個空間的數據,大家可能會擔心形成所謂的數據孤島,但是 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 語法把它展示成表視圖,在表空間里面有這么一個視圖,但它的數據其實用的是樹視圖里面寫下來的這個數據。這樣的話,原來用戶的樹模型、用戶所有的寫入代碼、原有的一些簡單的查詢代碼,其實都是不用改的,已存在的業務都不用改,只是新增了一些查詢場景,這些業務它可以通過表視圖用表的語法去查。這個還是一個比較有意思的功能,最大的收益點就是用戶可以同一份數據用兩種視圖去查,哪一種視圖對你更優,你就去選擇哪一種視圖。這個目前還在開發當中,在后續的版本會釋放出來。

表模型直播回顧圖16-20240303.png

還有一個概念跟大家強調一下,就是 IoTDB 并不是一個多模數據庫。多模數據庫是什么概念?它是一種新型的數據庫管理系統,能夠支持多種模型,這個模型就是不同類型的數據結構,比如說文檔數據庫、鍵值數據庫、KV 數據庫比如 Redis,圖形數據庫比如 Neo4j,時序數據庫比如 IoTDB,關系型數據庫 比如 MySQL,PostgreSQL 等等,這些是它的模型。那 IoTDB 其實剛剛也說了應該糾正一下,叫樹視圖和表視圖,只是大家基本上會把這兩個概念混起來,就叫樹模型跟表模型了。它底層都是同一種數據結構,也就是時序數據,它只是兩種視圖、兩種語法。這個后面也會介紹,我們去區分表語法跟樹語法的時候,它其實是通過 sql_dialect,也就是 SQL 方言的方式去指定的。從這邊也可以看出來,IoTDB 并不是一個多模數據庫,或者我們并沒有去擴展系統邊界,想去做一個多模數據庫。

表模型直播回顧圖17-20240303.png

這個也是用戶群里面大家比較關心的問題,我們怎么去升級?這里我把所有的 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 系列的版本也是一樣的。

表模型直播回顧圖18-20240303.png

更多內容推薦:

? 了解如何使用 IoTDB 企業版

? 了解更多 IoTDB 應用案例