隨著云原生時序數據庫(Time Series Database,TSDB) TDengine 3.0 的發布,很多用戶其(qi)實會(hui)好奇:“和(he) 2.0 比(bi)起來,3.0 有哪些直觀的優化(hua)呢?”
本文將以(yi) Update 這一功能的變化為(wei)例,具體介紹一下 3.0 的細(xi)致優化。
和 2.0 比起來,3.0 版本的 Update 不再需要參數配置,“部分列更新”成為數據庫本身的特性,并且還解決了 2.0 的 Update 機制的一些不足。
一、2.0 時代的 Update:
對(dui)于 TDengine 的 Update 功能,老(lao)用戶應(ying)該都比(bi)較清楚(chu):
在 2.0 版本(ben)中,TDengine 通過對(dui) database 級別參數值 “update” 的(de)配置,來完成(cheng)對(dui)相同時間戳行的(de)數據更(geng)新。
- update 為 0 ,不更新;
- update 為 1 ,整行更新,未指定值的列會被更新為 NULL;
- update 為 2,部分列更新,未指定值或者寫入 NULL 的列會保留原有值。
一(yi)開始,TDengine 只支持 update 為 1 (即(ji)整行更新)。但在很(hen)多場景下(xia),用戶往往不會在同一(yi)時間更新一(yi)張表中的所有(you)列,因此我們后續又支持了(le) update 為 2(即(ji)部(bu)分列更新)。
顯然,部(bu)分(fen)列(lie)更新(xin)(xin)更為靈活(huo),因為它(ta)既可(ke)以做到整(zheng)行更新(xin)(xin),又可(ke)以做到局部(bu)更新(xin)(xin)。但是通過它(ta)的邏(luo)輯,我(wo)們(men)或許會有(you)(you)這樣(yang)的疑(yi)問:如(ru)果我(wo)想把一個值更新(xin)(xin)為 NULL 值,應該怎么辦呢?這個疑(yi)問是有(you)(you)道理的。不過 2.0 版本并不支持這樣(yang)的更新(xin)(xin)。
在(zai) 2.0 的版本中(zhong),數據可以被分(fen)為兩(liang)大類 NORMAL 和 NULL 。 NORMAL 類代表(biao) TDengine 所有數據類型中(zhong)的非(fei)空(kong)值(zhi)字面(mian)(mian)量(liang),而 NULL 則代表(biao)所有數據類型的空(kong)值(zhi)字面(mian)(mian)量(liang)。
當 Update 行為發生時,它的邏輯(ji)是 :如(ru)果在(zai)某(mou)一行 insert 語句中沒有顯式寫入某(mou)一列(lie)值(zhi)的話(hua),會(hui)認為該列(lie)輸入了 NULL 值(zhi)。
所以(yi)下(xia)面這兩種寫(xie)法的語義其實是一樣(yang)的。

- insert into t1 (ts,num1,num2) values (“xxxx”,1,2) ;
- insert into t1 values (“xxxxx”,1,2,NULL) ;
所以在 update 為 1 時,上述兩個(ge) SQL 都會用 NULL 值會覆蓋掉 num3 原(yuan)有的值。
而在 update 為(wei) 2 時,上述兩個 SQL 又(you)都會保留(liu) num3 原有的(de)值。
因此,上述設(she)定(ding)會導致 2.0 版(ban)本(ben)無法把一個值更新為 NULL 值。
二、3.0 時代的 Update:
為(wei)了避免這一問(wen)題,從 3.0 版本開始,TDengine 引(yin)入了 None 值(未賦值)語(yu)義——當用(yong)戶進行 insert 輸入時(shi),如果未對某一列進行顯(xian)式輸入(如上面的 SQL 語(yu)句 1),taosc 不再將其(qi)置為(wei) NULL,而是將該列標識(shi)為(wei) None(對外查詢仍顯(xian)示為(wei) Null)。
因(yin)此(ci),仍然以上述(shu)兩個 SQL 為例(li),在 3.0 版(ban)本的 Update 場景中(zhong),它們已經有了不(bu)同(tong):
- Insert into t1 (ts,num1,num2) values (“xxxxx”,1,2); (對于 num3 列, 標記為 NONE)
- insert into t1 values (“xxxxx”,1,2,NULL);(對于 num3 列, 標記為 NULL)
而(er) 3.0 的(de)(de) Update 規則為:如果寫入的(de)(de)是(shi) NORMAL/NULL ,那么(me)就取(qu)版本號(hao)比(bi)較大的(de)(de)行,如果我寫入的(de)(de)是(shi) NONE,那么(me)就取(qu)版本號(hao)比(bi)較小的(de)(de)行,所以:
- SQL 語句 1 會把 t1 表的 num1 和 num2 列都更新成最值,num3 保持原樣(因為 num3 要和 NONE 取版本比較小的行);
- SQL 語句 2 會把 t1 表的 num1 和 num2 列都更新成最值,num3 更新成 null(因為 num3 要和 NULL 取版本比較大的行)。
由上可見,由于(yu) NONE 的(de)(de)引入,3.0 已經可以在無需任何配置的(de)(de)情況(kuang)下,以部分列更新模式來(lai)進行數據更新了(le)。
可以用這幾條簡(jian)單的 SQL 來體驗 TDengine 的這個(ge)新特性:
CREATE TABLE `t1` (`ts` TIMESTAMP, `num1` INT, `num2` INT, `num3` INT);
insert into t1 values ("2020-01-01 01:00:00",1,1,1);
insert into t1 (ts,num1,num2) values ("2020-01-01 01:00:00",2,2);
insert into t1 values ("2020-01-01 01:00:00",3,3,null);
三、更新邏輯
其(qi)實,TDengine 不論是(shi)在 2.0 還是(shi) 3.0 時代,更(geng)(geng)(geng)新(xin)(xin)的(de)(de)邏輯都(dou)是(shi)類似的(de)(de):3.0 是(shi)不論在硬盤(pan)(pan)還是(shi)內(nei)存的(de)(de)數(shu)(shu)據(ju)都(dou)只(zhi)是(shi)標記更(geng)(geng)(geng)新(xin)(xin)(寫入時間戳相同的(de)(de)數(shu)(shu)據(ju)會生成子數(shu)(shu)據(ju)塊(kuai)),而 2.0 內(nei)存中(zhong)的(de)(de)數(shu)(shu)據(ju)是(shi)物(wu)理更(geng)(geng)(geng)新(xin)(xin),硬盤(pan)(pan)上(shang)是(shi)標記更(geng)(geng)(geng)新(xin)(xin)。在查詢(xun)的(de)(de)時候,他們(men)都(dou)是(shi)先把原本(ben)的(de)(de)數(shu)(shu)據(ju)塊(kuai)和子數(shu)(shu)據(ju)塊(kuai)從硬盤(pan)(pan)上(shang)讀(du)取到內(nei)存中(zhong),再通過被高版本(ben)覆(fu)蓋(gai)(gai)或被低(di)版本(ben)覆(fu)蓋(gai)(gai)的(de)(de)方式完(wan)成某(mou)列數(shu)(shu)據(ju)的(de)(de)更(geng)(geng)(geng)新(xin)(xin)或保(bao)留,然后再把它(ta)們(men)與原先存在于內(nei)存中(zhong)的(de)(de)數(shu)(shu)據(ju)合并處理,最后把結果(guo)返回給(gei)客戶端。
不過,與 2.0 比起來(lai),3.0 使用了(le) multi-version (多版本模式(shi)),這(zhe)是由于(yu) 2.0 的(de)更新、刪(shan)除(chu)功(gong)能不是一開始就有的(de),而是后(hou)期(qi)逐步增加的(de)實(shi)現,有點像(xiang)打補丁(ding),不夠優(you)雅。所(suo)以 3.0 相(xiang)當于(yu)把(ba)這(zhe)些割裂的(de)功(gong)能,從存儲引擎底部做了(le)一次優(you)化融合,也(ye)大幅提(ti)升了(le)用戶體驗,以這(zhe)個 Update 功(gong)能為例(li),用戶不再需(xu)要(yao)任何配置,只需(xu)要(yao)知(zhi)道 TDengine 的(de)更新方(fang)式(shi)就可(ke)以了(le)。
而關于 3.0 的存儲引擎的底層優化具體詳情,可以通過這篇文章進一步了解。
四、結語
3.0 上有很(hen)多類似這樣的優化和重構。之后我們會持續以文章視頻等形(xing)式,帶領大家深入探索這款(kuan)云原生的時序數(shu)據庫,一起為(wei)企業(ye)帶來(lai)價值,為(wei)開(kai)發者(zhe)帶來(lai)成功。


























