如何設(shè)計(jì)時(shí)序數(shù)據(jù)表
時(shí)序數(shù)據(jù)表可以為您提高查詢和存儲(chǔ)性能,本文介紹如何根據(jù)時(shí)序數(shù)據(jù)的來源和場(chǎng)景建立時(shí)序數(shù)據(jù)表。
時(shí)序數(shù)據(jù)示例
時(shí)序數(shù)據(jù)建模至關(guān)重要,需要仔細(xì)分析數(shù)據(jù)來源的特性和查詢的場(chǎng)景,建立合理的數(shù)據(jù)表,以便達(dá)到最佳的存儲(chǔ)和查詢性能。以下圖的空氣檢測(cè)數(shù)據(jù)為例:
每個(gè)時(shí)間點(diǎn)對(duì)應(yīng)的數(shù)據(jù)記錄可以詳細(xì)分為幾個(gè)部分:
表(Table):代表一系列同類時(shí)序數(shù)據(jù)的集合。
標(biāo)簽(Tags):表明指標(biāo)項(xiàng)監(jiān)測(cè)針對(duì)的具體對(duì)象屬性。其中一個(gè)標(biāo)簽(Tag)由一個(gè)標(biāo)簽鍵(Key)和一個(gè)對(duì)應(yīng)的標(biāo)簽值(Value)組成。時(shí)序引擎默認(rèn)會(huì)為每一個(gè)標(biāo)簽的鍵-值對(duì)都建立標(biāo)簽與時(shí)間序列之間的索引。在特定場(chǎng)合下,標(biāo)簽也可能會(huì)有不同的叫法,例如可能被稱為Labels或者Dimensions。
時(shí)間戳(Timestamp):表示該數(shù)據(jù)記錄對(duì)應(yīng)的生成時(shí)間。
字段(Field):一條數(shù)據(jù)記錄可以有多個(gè)字段值,表示指標(biāo)的不同方面。時(shí)序引擎不會(huì)為字段建立索引。
表設(shè)計(jì)的最佳實(shí)踐
基于以上的數(shù)據(jù)模型,我們便可以將同一類時(shí)序數(shù)據(jù)的度量(如上圖中的AQM)設(shè)計(jì)為表名,并按照SQL的CREATE TABLE語法進(jìn)行表設(shè)計(jì)。
以上文的空氣質(zhì)量監(jiān)測(cè)的時(shí)序模型為例,可以采用的表定義如下所示。
CREATE TABLE aqm (
city VARCHAR TAG,
district VARCHAR TAG,
id VARCHAR TAG,
time TIMESTAMP,
pm2_5 DOUBLE,
pm10 DOUBLE,
so2 DOUBLE,
no2 DOUBLE,
PRIMARY KEY(id) ////單機(jī)版實(shí)例不支持PRIMARY KEY,如果使用的是單機(jī)版實(shí)例,請(qǐng)刪除此行
);
在此定義基礎(chǔ)上,隨后向表中寫數(shù)據(jù)便可通過INSERT語句來進(jìn)行:
INSERT INTO aqm (city, district, id, time, pm2_5, pm10, so2, no2)
VALUES ('hangzhou', 'yuhang', 'HY00001', '2019-04-18 10:00:00', 31.0, 66.0, 10.0, 43.0);
INSERT INTO aqm (city, district, id, time, pm2_5, pm10, so2, no2)
VALUES ('hangzhou', 'yuhang', 'HY00001', '2019-04-18 10:01:00', 31.2, 66.0, 10.5, 43.1);
也可以通過下述INSERT語句實(shí)現(xiàn)批量寫入數(shù)據(jù)。
INSERT INTO aqm (city, district, id, time, pm2_5, pm10, so2, no2)
VALUES ('hangzhou', 'yuhang', 'HY00001', '2019-04-18 10:02:00', 31.3, 66.0, 10.0, 42.9),
('hangzhou', 'yuhang', 'HY00001', '2019-04-18 10:03:00', 31.2, 66.4, 10.3, 43.0);
關(guān)鍵字TAG是時(shí)序引擎對(duì)SQL的語法擴(kuò)展,用于將表中的部分列標(biāo)示為“標(biāo)簽”。為避免在時(shí)序數(shù)據(jù)建表的過程中糾結(jié)于應(yīng)該將哪些字段應(yīng)定義為TAG,建議嘗試遵循以下原則:
能夠標(biāo)示數(shù)據(jù)采集源屬性的字段定義為TAG,特別是能夠唯一標(biāo)示數(shù)據(jù)源的屬性。
應(yīng)避免使用進(jìn)程ID,時(shí)間關(guān)聯(lián)屬性等易變值作為標(biāo)簽,即便這類屬性的類型是字符串,仍然建議將其定義為Field。如果使用此類易變屬性作為標(biāo)簽,將會(huì)導(dǎo)致時(shí)間線數(shù)量急劇膨脹,并帶來時(shí)間線索引大小劇增,反而不利于查詢。
PRIMARY KEY設(shè)計(jì)的最佳實(shí)踐
數(shù)據(jù)庫會(huì)根據(jù)PRIMARY KEY進(jìn)行存儲(chǔ)分片與查詢優(yōu)化,指定PRIMARY KEY的查詢請(qǐng)求將會(huì)非常高效,強(qiáng)烈建議建表時(shí)指定。
單機(jī)版實(shí)例不支持PRIMARY KEY。
通常建議選擇數(shù)據(jù)源的唯一標(biāo)識(shí)作為PRIMARY KEY,場(chǎng)景示例如下:
物聯(lián)網(wǎng)、工業(yè)互聯(lián)網(wǎng)場(chǎng)景,可以采用設(shè)備ID作為PRIMARY KEY。
車聯(lián)網(wǎng)場(chǎng)景,可以采用車輛唯一標(biāo)識(shí)來作為PRIMARY KEY。
監(jiān)控場(chǎng)景,可以采用APP ID或者h(yuǎn)ost:port等標(biāo)識(shí)作為PRIMARY KEY。
以上述時(shí)序數(shù)據(jù)表aqm的示例,如果業(yè)務(wù)存在大量基于ID的查詢,則指定ID作為PRIMARY KEY是最佳選擇。
CREATE TABLE aqm (
city VARCHAR TAG,
district VARCHAR TAG,
id VARCHAR TAG,
time TIMESTAMP,
pm2_5 DOUBLE,
pm10 DOUBLE,
so2 DOUBLE,
no2 DOUBLE,
PRIMARY KEY (id) //單機(jī)版實(shí)例不支持PRIMARY KEY,如果使用的是單機(jī)版實(shí)例,請(qǐng)刪除此行
);
和傳統(tǒng)的關(guān)系型數(shù)據(jù)庫不同,在時(shí)序數(shù)據(jù)表中定義為PRIMARY KEY的列并不要求列的值遵循唯一性約束,但是需要出現(xiàn)在PRIMARY KEY列表中的列名必須是標(biāo)簽列。
數(shù)據(jù)類型選擇的最佳實(shí)踐
時(shí)序引擎當(dāng)前支持的數(shù)據(jù)類型可參見數(shù)據(jù)類型。對(duì)于時(shí)序數(shù)據(jù)表的創(chuàng)建,各種列的數(shù)據(jù)類型選擇的建議如下:
標(biāo)簽(Tag)列
聲明為TAG的列固定為VARCHAR類型,無法更改。
時(shí)間戳(Timestamp)列
在存儲(chǔ)引擎時(shí)間戳實(shí)際上會(huì)按照BIGINT類型統(tǒng)一存為Epoch時(shí)間戳以便實(shí)現(xiàn)更優(yōu)的時(shí)間戳壓縮。但用戶可結(jié)合對(duì)時(shí)間戳的計(jì)算需求自行選擇在建表時(shí)使用BIGINT類型或TIMESTAMP類型。
字段(Field)列
理論上字段列可選擇使用所有數(shù)據(jù)類型。但出于數(shù)據(jù)壓縮和查詢計(jì)算的角度考慮,應(yīng)盡量避免使用VARCHAR類型作為字段列的類型。