天天看點

寫給關系資料庫開發者的 TDengine 入門指南

MySQL 是中國開發者最熟悉的開源資料庫産品,在很多開發者心中 MySQL 就是關系資料庫的代名詞。開發者們對 MySQL 資料庫的的特性已經非常熟悉了。

TDengine (https://github.com/taosdata/TDengine)是完全面向處理時序資料而設計的資料庫,是資料庫領域的“新物種”,也就是所謂的時序資料庫(Time Series Database,簡稱 TSDB)。TDengine 在創立伊始,就堅定地走相容 SQL 的路線,這極大地降低了資料庫使用者的使用門檻,但是另一方面,時序資料和關系資料庫的處理方式還是有些差別,是以熟悉 MySQL 的使用者在入手 TDengine 的時候會有一些混淆。是以,我們專門撰寫了這篇文章,希望可以幫助廣大熟悉 MySQL 資料庫的開發者更快地上手 TDengine。

但同時我們也要指出,TDengine 是專門為處理時序資料而設計的産品,并不适合存儲非時序類型資料,在實際應用中,可以結合關系型資料庫一起使用。

注:本文以最新的 TDengine 3.0.1.4 版本為例。

時序資料模組化

用 MySQL 關系型資料庫給時序資料模組化

為了友善大家了解,我們先用大家熟悉的關系型資料庫進行模組化。模組化的場景是我們要采集一萬個電表的資料,每個電表有自己的裝置 ID(device_id),有所在的位置(location),電表有不同型号(group_id)。每次采集我們要記錄當時的時間戳(ts)、電表的電流(current)、電壓(voltage)、相位(phase)三個資料。

建立資料庫的 SQL 語句:

CREATE SCHEMA `test`;
           

表 meters

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

建立表 meters 的 SQL 語句:

CREATE TABLE `test`.`meters` (
  `device_id` VARCHAR(8) NOT NULL,
  `ts` TIMESTAMP(3) NOT NULL,
  `current` FLOAT NULL,
  `voltage` INT NULL,
  `phase` FLOAT NULL,
  PRIMARY KEY (`device_id`, `ts`),
  CONSTRAINT `FK_meters_devices`
    FOREIGN KEY (`device_id`)
    REFERENCES `test`.`devices` (`device_id`));
           

表 devices

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

建立表 devices 的 SQL 語句:

CREATE TABLE `test`.`devices` (
  `device_id` VARCHAR(8) NOT NULL,
  `location` VARCHAR(24) NOT NULL,
  `group_id` INT NOT NULL,
  PRIMARY KEY (`device_id`),
  INDEX `IDX_location` (`location` ASC),
  INDEX `IDX_group_id` (`group_id` ASC));
           

把 MySQL 模組化轉換成 TDengine 模組化

我們來對比看看 TDengine 的模組化和 MySQL 有什麼不同。讓我們先引入 TDengine 的兩個概念:

1、一個裝置采集點一張表

根據這一設計,device_id 就是子表名稱。location 和 group_id 我們作為子表的 TAG。主鍵:在 TDengine 中,表的第一個字段必須是 TIMESTAMP 類型,并且會被自動設定為主鍵。

2、超級表與子表

在一個裝置采集點一張表的設計理念下,對應裝置的數量,會出現成千上萬乃至上億張表,TDengine 為此又引入了“超級表”和“子表”兩個概念,它們有如下幾個主要特征:

  • 超級表是子表的模闆,定義了子表的資料結構,所有子表都是由超級表“派生”出來,修改超級表結構就是修改所有子表結構;
  • 基于超級表可以輕松進行分組聚合查詢,查出每個子表的聚合計算後的資料,如:查詢每個電表的總用電量;
  • 标簽(TAG)可以了解為定義在超級表中的字段,每一個子表隻有一組标簽值,代表一個采集點的靜态資料且為記憶體存儲。在 SELECT 語句查詢的時候,标簽(TAG)值可以像普通字段一樣出現在查詢結果中。

更多 TDengine 超級表文檔請參考:https://docs.taosdata.com/taos-sql/stable/。

現在讓我們用 TDengine 進行模組化,建立資料庫的 SQL 語句:

CREATE DATABASE `test`;
           

然後建立一張超級表:

表 meters

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

建立表 metrics 的 SQL 語句:

CREATE STABLE `test`.`meters` (
  `ts` TIMESTAMP,
  `current` FLOAT,
  `voltage` INT,
  `phase` FLOAT)
TAGS (
  `group_id` INT,
  `location` VARCHAR(24));
           

關于資料類型的對比

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

TDengine 資料類型文檔請參考:https://docs.taosdata.com/taos-sql/data-type/。

關鍵字和保留詞

MySQL 和 TDengine 的關鍵字/保留詞略有不同,是以有些情況下建立表名、字段名時候,需要注意加上反引号 “ 進行轉義。舉例:

  • TTL 在 TDengine 中是關鍵字,但在 MySQL 中不是。
  • CURRENT 在 MySQL 中是關鍵字,但在 TDengine 中不是。

資料插入與更新

下面讓我們來體驗下資料處理的真執行個體子:

插入采集資料

MySQL

插入裝置資料

按照上面的模組化,MySQL 插入資料之前,需要先準備好裝置資料,下面我們準備幾條:

INSERT INTO `test`.`devices` VALUES ('d1001', 'California.SanFrancisco', 2);
INSERT INTO `test`.`devices` VALUES ('d1002', 'California.SanFrancisco', 3);
INSERT INTO `test`.`devices` VALUES ('d1003', 'California.LosAngeles', 3);
           

插入采集資料

INSERT INTO `test`.`meters` VALUES ('d1001', '2018-09-08 17:51:04.777', 10.3, 219, 0.31);
INSERT INTO `test`.`meters` VALUES ('d1002', '2018-09-08 17:51:04.777', 10.2, 220, 0.23);
INSERT INTO `test`.`meters` VALUES ('d1003', '2018-09-08 17:51:04.777', 11.5, 221, 0.35);
           

TDengine

建立子表

因為 TDengine 的裝置屬性通過标簽(TAG)的方式表達,是以在建立子表的時候來定義裝置的屬性(對應 MySQL 的插入裝置資料)。讓我們先來建立子表:

CREATE TABLE `test`.`d1001` USING `test`.`meters` (`group_id`, `location`) TAGS (2, "California.SanFrancisco");
CREATE TABLE `test`.`d1002` USING `test`.`meters` (`group_id`, `location`) TAGS (3, "California.SanFrancisco");
CREATE TABLE `test`.`d1003` USING `test`.`meters` (`group_id`, `location`) TAGS (3, "California.LosAngeles");
           

以上語句的語義是通過使用(USING)超級表

test

.

meters

,來建立對應标簽(TAGS)的子表。

插入采集資料

INSERT INTO `test`.`d1001` VALUES ('2018-09-08 17:51:04.777', 10.3, 219, 0.31);
INSERT INTO `test`.`d1001` VALUES ('2018-09-08 17:51:04.777', 10.2, 220, 0.23);
INSERT INTO `test`.`d1001` VALUES ('2018-09-08 17:51:04.777', 11.5, 221, 0.35);
           

插入采集資料時自動建立子表

TDengine 還有更便捷的方式,可以讓建立子表和插入資料在同一條語句中實作:

INSERT INTO `test`.`d1001` USING `test`.`meters` TAGS ('California.SanFrancisco', 2) VALUES ('2018-09-08 17:51:04.777', 10.3, 219, 0.31);
           

關于寫入資料的詳細文檔,請參考:https://docs.taosdata.com/taos-sql/insert/。

更新采集資料

MySQL

我們先來看看 MySQL 如何更新資料:

更新采集資料:

UPDATE `test`.`meters` SET `ts` = '2018-09-08 17:51:07', `current` = 10.4, `voltage` = 220, `phase` = 0.32 WHERE `device_id` = 'd1001' and `ts` = '2018-09-08 17:51:05';
           

TDengine

TDengine 中沒有 UPDATE 語句,但是 TDengine 也支援更新。在 TDengine 中,INSERT 時間戳相同的資料,會更新原有記錄:

INSERT INTO `test`.`d1001` VALUES ('2018-09-08 17:51:04.777', 10.4, 225, 0.35);
           

注意:TDengine 2.x 版本需要在建立資料庫時指定 UPDATE 參數,3.x 版本不需要。

更新裝置屬性

MySQL

我們先來看看 MySQL 模組化下如何更新裝置屬性:

UPDATE `test`.`devices` SET `location` = 'California.LosAngeles', `group_id` = 3 WHERE `device_id` = 'd1001';
           

TDengine

如前文所述,TDengine 的裝置屬性存在于标簽(TAG)之中,修改裝置屬性就是修改标簽,是以要用修改标簽的語句:

ALTER TABLE `test`.`d1001` SET TAG `location` = 'California.LosAngeles';
ALTER TABLE `test`.`d1001` SET TAG `group_id` = 5;
           

注:标簽隻可單個修改。

工具與可視化

GUI 工具

MySQL 官方從 5.0 版本開始提供了 MySQL Workbench 這個圖形管理工具,目前 TDengine 還未提供官方的 GUI 管理工具,但是因為 TDengine 支援 JDBC 标準驅動,這就讓 TDengine 可以通過 JDBC 驅動直接對接目前市面上大量的 SQL IDE 産品,比如 DBeaver、IDEA 等。TDengine 官方也提供了相關文檔,供參考:

如何通過開源資料庫管理工具 DBeaver 連接配接 TDengine

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

如何通過 IDEA 資料庫管理工具連接配接 TDengine?

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

此外,TDengine 企業版提供了 Taos Explorer,提供專門适配 TDengine 技術架構的完整 GUI 管理工具。如果你想使用 Taos Explorer,也可以直接聯系官方企業咨詢服務:https://www.taosdata.com/support。

可視化

TDengine 官方已經适配了 Grafana,在 Grafana 官方插件庫裡可以找到,詳情請參考 TDengine 官方文檔:https://docs.taosdata.com/third-party/grafana/。

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

導入導出工具

MySQL 官方提供了 mysqldump 工具用來進行資料的導入和導出。同樣的,TDengine 官方也提供了 taosdump 工具來進行相同的任務。詳情請參考官方文檔:https://docs.taosdata.com/operation/import/ 和https://docs.taosdata.com/operation/export/。

容量與查詢性能對比

環境與資料準備

裝置環境:MacBook Pro 14 M1 8-core 16GB

MySQL 版本:8.0.28

TDengine 版本:3.0.1.4

我們通過使用 taosBenchmark 工具(https://docs.taosdata.com/reference/taosbenchmark),來随機生成一億條采集資料,分布在一張超級表 meters 下的一萬張子表中,并把相同的資料按上述模組化模型導入進 MySQL,確定最後的比對結果一緻。

存儲空間對比

針對上述資料,MySQL 實際存儲空間為 4,931 MB,TDengine 存儲空間為 493 MB。

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

查詢性能對比

典型查詢一(COUNT)

SELECT COUNT(*) FROM `test`.`meters`;
           

MySQL

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

TDengine

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

總結:TDengine 查詢性能是 MySQL 的 50 倍

典型查詢二(平均值,最大值、最小值)

SELECT AVG(voltage) FROM `test`.`meters`;
SELECT MAX(voltage) FROM `test`.`meters`;
SELECT MIN(voltage) FROM `test`.`meters`;
           

注:經過測試,MySQL 和 TDengine 對 AVG()、MAX()、MIN() 函數的查詢時間均類似,是以不再額外展示。

MySQL

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

TDengine

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

典型查詢三(條件查詢)

MySQL

SELECT COUNT(*) FROM `test`.`meters` m INNER JOIN `test`.`devices` d ON m.device_id = d.device_id WHERE d.location = "California.MountainView";
           

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

TDengine

SELECT COUNT(*) FROM `test`.`meters` WHERE location = "California.MountainView";
           

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

典型查詢四(分組查詢)

MySQL

SELECT AVG(m.voltage), d.location FROM `test`.`meters` m INNER JOIN `test`.`devices` d ON m.device_id = d.device_id GROUP BY d.location;
           

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

TDengine

SELECT AVG(voltage), location FROM `test`.`meters` GROUP BY location;
           

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

典型查詢五(時序業務)

MySQL

SELECT DATE_FORMAT(ts, '%Y%m%d-%H') AS date_format, AVG(voltage) FROM `test`.`meters` GROUP BY date_format;
           

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

TDengine

SELECT AVG(voltage) FROM `test`.`meters` INTERVAL(1h);
           

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

TDengine 的特色功能(時序資料處理)

TDengine 在支援标準 SQL 的基礎之上,還提供了一系列滿足時序業務場景需求的特色查詢文法,這些文法能夠為時序場景的應用的開發帶來極大的便利。

時間視窗切分查詢

TDengine 支援按時間視窗切分方式進行聚合結果查詢,比如需查詢每隔 1 秒鐘的電流平均值。舉例:

SELECT _wstart, AVG(current) FROM `test`.`d1001` INTERVAL(1s);
           

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

狀态視窗切分查詢

使用整數(布爾值)或字元串來辨別産生記錄時候裝置的狀态量。産生的記錄如果具有相同的狀态量數值則歸屬于同一個狀态視窗,數值改變後該視窗關閉。舉例:

SELECT COUNT(*), FIRST(ts), voltage FROM `test`.`meters` STATE_WINDOW(voltage) LIMIT 10;
           

::: hljs-center

寫給關系資料庫開發者的 TDengine 入門指南

:::

資料保留政策

經過長時間累積大量資料以後,曆史資料往往需要做歸檔或删除處理。MySQL 等關系型資料庫隻能通過執行計劃任務調用 DELETE 語句根據時間條件删除資料。而 TDengine 天生就對資料保留政策提供了支援,一共有三種辦法來靈活地處理:

  • 建立資料庫時,設定 KEEP 參數,比如 CREATE DATABASE test KEEP 100d; 表示資料庫中的資料在儲存 100 天後會被自動删除;
  • 建立表時,設定 TTL 參數,機關為天,比如 CREATE TABLE meters ... TTL 50; 表示 50 天之後,表會被系統自動删除;
  • 冷熱資料分級存儲。在 TDengine 企業版中,支援把資料按照時間次元分别存儲于不同的檔案句柄,可以對應到不同的存儲媒體,比如将熱資料存儲于 SSD 磁盤,将冷資料存儲到 S3 存儲中。

替代 MySQL 案例分享

  • 存儲空間降為 MySQL 的十分之一,TDengine 在貨拉拉資料庫監控場景的應用
  • MySQL 無法滿足查詢性能?北明天時選擇 TDengine 實作熱網監控和能源分析
  • 接手被 MySQL 卡死的資料,TDengine 在能源管理系統的應用
  • MySQL 當機?大資料驅動下的新零售,如何尋求存儲計算的最優解?