
一、金倉時序數據庫超表架構難在哪先撂個結論手工分表這套辦法毛病不在“分”上在于分完之后所有的活兒都得你自己干。做過時序數據的人應該都懂。按月建表嘛xxx_202501、xxx_202502一路往下排。寫入靠應用層拼表名做路由查跨月的數據就 UNION ALL 一串。量小的時候是真沒毛病甚至可以說還挺優雅。可數據一上來麻煩就開始一個接一個往外蹦。最先繃不住的往往是分區規則。它散落在代碼里啊建表靠定時任務路由邏輯埋在應用里頭。新同事不知道有這套約定改查詢忘了帶月份路由一條 SQL 直接掃當月大表。這種事幾乎每個團隊都出過出一次記一輩子。然后是跨月查詢。UNION ALL 完再聚合你自己琢磨琢磨各表上的索引不就白建了嘛。月份跨得越多越慢沒有例外。冷熱數據還混著放。三個月前的明細除了出報表那天誰碰它啊可它偏偏和今天的熱數據躺同一塊盤上磁盤告警三天兩頭來報到。刪又不敢刪鬼知道哪張報表哪天要用。到期刪舊數據這事兒靠人惦記忘了就堆著堆著堆著就成了誰也不敢動的歷史包袱。想擴容就剩換更貴的服務器一條道賬單蹭蹭漲。這些麻煩攤開來看根子其實就一個問題分區這件事到底歸誰管手工分表時代它歸應用管所以樁樁件件都得人扛。金倉的超表Hypertable治的就是這個。它把分區的活兒整個下沉到數據庫里頭去了。數據進來按時間自動切成一個個數據塊Chunk每塊只管一段時間的再疊個空間維度比如按點位 ID 哈希把高并發寫入攤開。應用這邊看到啥從頭到尾就一張monitor_point_dataINSERT 該咋寫咋寫。查半年的數據也是一條普普通通的 SQL跟你當前時間區間沒關系的塊數據庫自己就不碰了。兩種模式擺一塊兒對比下對比項手工分表金倉超表分區誰管應用建表定時任務規則散在代碼里數據庫自己按時間空間切 Chunk跨時段查詢多表 UNION ALL索引廢掉一條普通 SQL沒關的塊直接不碰寫入路由應用按時間拼表名不存在這個環節直接插老數據治理手工 DROP忘了就堆著到期自動按塊刪以后擴容堆硬件燒錢可以往分布式超表走SQL 兼容-標準 SQLBI 工具直連靠 SQL 吃飯的團隊最后一行搞不好才是最香的。報表工具、BI 看板、備份腳本、監控探針、權限體系全能接著用不用為時序能力單獨搭一條工具鏈。人就那么幾個的小團隊這點比啥跑分都實在。不過丑話說前頭超表只是把復雜度從應用層挪到了數據庫層它可沒消失。塊間隔、壓縮、保留策略、連續聚合這套新機制各有各的坑坑跟坑之間還會互相影響。下面按落地的順序一個一個說。目錄一、金倉時序數據庫超表架構難在哪二、建表三、第一個坑塊間隔四、壓縮和保留五、第二個坑刷新窗口和保留策略會互相咬六、幾句經驗二、建表先建張普通表就你平時寫的那種一點特殊語法都沒有CREATETABLEmonitor_point_data(timeTIMESTAMPTZNOTNULL,point_idINTEGERNOTNULL,metricTEXTNOTNULL,valueDOUBLEPRECISION,qualitySMALLINT);-- 轉為超表時間列做主分區point_id 哈希做空間分區SELECTcreate_hypertable(monitor_point_data,time,partitioning_columnpoint_id,number_partitions8,chunk_time_intervalINTERVAL1 day);一個函數調用完事兒。時間軸按chunk_time_interval自動滾新塊空間軸按點位 ID 哈希成 8 個分區。應用側要做的改造就是把原來拼表名那段代碼刪掉。有個約束得提前講省得對著報錯發半天呆唯一索引必須帶上分區列。想拿point_id這種單列做唯一約束數據庫直接給你彈回來報錯還老長一段。道理不復雜每個 Chunk 各自建索引數據庫沒法跨塊替你保證唯一性所以唯一索引里必須把時間列捎上。三、第一個坑塊間隔塊間隔這個參數直覺上特別容易犯一個錯覺得塊切得越小查詢越快上來就設個 1 小時。直說了吧會翻車。塊切太細后臺建新塊的頻率就飛起寫入高峰還會莫名其妙冒出鎖等待。為啥建新塊要拿的鎖比往已有塊里插數據拿的鎖時間長。一堆事務擠在同一時刻搶著開新塊可不就互相頂死了嘛。那到底設多大手冊里有參考值按日寫入量給的每天寫 2GB、內存 64GB 的機器7 天一塊正合適一天寫到 10GB縮到 1 天一塊。所以原則就一句話先抄手冊的作業再按自己的量微調。直覺在這兒不值錢。運行中想調也有接口但藏著個語義坑-- 注意只對之后新建的塊生效已經建好的塊不動SELECTset_chunk_time_interval(monitor_point_data,INTERVAL24 hours);-- 看看當前分區配置長啥樣SELECTcolumn_name,num_partitions,time_intervalFROMtimescaledb_information.dimensionsWHEREhypertable_namemonitor_point_data;改間隔只管新塊舊塊一個不碰。也就是說塊間隔設大了想改小舊塊是救不回來的。要么干等它自己滾出保留期要么老老實實遷數據。這參數務必上線前定死。四、壓縮和保留先問一句一個月之前的明細除了出報表那天還有誰碰它沒人碰。時序數據的訪問模式就是這么有規律最近的數據天天查老數據出了報表就沒人搭理了。壓縮策略照著這個規律配就行近幾天原樣擱著更老的塊自動壓成列存。ALTERTABLEmonitor_point_dataSET(timescaledb.compress,timescaledb.compress_segmentbypoint_id,timescaledb.compress_orderbytime DESC);-- 超過 7 天的塊自動壓縮SELECTadd_compression_policy(monitor_point_data,compress_afterINTERVAL7 days);-- 原始明細保留 180 天到期自動刪塊SELECTadd_retention_policy(monitor_point_data,drop_afterINTERVAL180 days);配置里兩個參數說下作用。compress_segmentby是按哪列分組壓縮時序場景一般挑設備或者點位 ID。compress_orderby是組內按啥排通常就填時間列。這倆選對了壓縮比和查詢效率都跟著受益實測壓縮比 4:1 上下跟官方口徑基本對得上。順帶提個不大但挺陰的細節壓縮塊上沒法直接加帶默認值的列要加得先解壓。嫌解壓麻煩也有變通加個可空列再 UPDATE 把值補上就這么繞過去。五、第二個坑刷新窗口和保留策略會互相咬報表聚合慢靠連續聚合治。思路不玄乎把小時級的聚合結果提前物化成一張特殊的超表后臺按策略增量刷新查詢直接拿現成的不碰明細。CREATEMATERIALIZEDVIEWpoint_data_hourlyWITH(timescaledb.continuous)ASSELECTpoint_id,time_bucket(INTERVAL1 hour,time)ASbucket,avg(value)ASavg_val,max(value)ASmax_val,min(value)ASmin_valFROMmonitor_point_dataGROUPBYpoint_id,bucketWITHNODATA;SELECTadd_continuous_aggregate_policy(point_data_hourly,start_offsetINTERVAL3 days,end_offsetINTERVAL1 hour,schedule_intervalINTERVAL30 minutes);下面這個坑我個人認為是整套方案里最容易翻車的必須單獨拎出來說。很多人配這倆策略的時候是分開想的保留策略拍一個數刷新窗口拍另一個數各管各的看著多合理啊。但它們實際上會互相咬。你保留 30 天刷新窗口也伸到 30 天前會咋樣聚合刷新跑到那個時間段一看源數據讓保留策略給刪了那它就把物化好的結果也順手刪了。注意這整個過程沒有報錯。沒告警沒異常日志就是報表上的數字悄無聲息地沒了。直到哪天有人盯著一條空曲線問數據咋回事你才知道壞了。這種靜默失敗排查起來最磨人。正確姿勢就一條保留周期要遠大于刷新窗口。照上面例子那樣保留 180 天、刷新窗口只伸到 3 天前讓刷新永遠落在還有原始數據的時段里這坑就踩不著。手冊里對這個組合是有明確警告的別問我為啥知道得這么清楚。日常查趨勢還是普通 SQL配個時間桶函數要多細有多細SELECTtime_bucket(5 minutes,time)ASfive_min,avg(value)ASavg_valFROMmonitor_point_dataWHEREpoint_id1024ANDtimenow()-INTERVAL2 hoursGROUPBYfive_minORDERBYfive_min;六、幾句經驗回頭看超表落地這事技術上真不難難的是心態。把原來攥在自己手里那點“分表智慧”整個交還給數據庫交出去那幾天是真沒底老琢磨它真能替我管好幾條經驗擱這兒。塊間隔先抄作業再微調按日寫入量對照手冊來。這參數改小只對新塊生效設大了想縮沒有回頭路。唯一索引必須帶分區列單列唯一約束直接報錯把時間列加上就好。保留策略和刷新窗口必須一起設計。這條得再說一遍因為這倆配岔了連報錯都沒有數據就這么沒了。壓縮塊上別直接加帶默認值的列先解壓或者可空列加 UPDATE 繞過去。還有個容易忽略的超表的價值不止“快”那一下。應用代碼干凈了團隊里沒人再需要搞懂那套分表路由的約定。這種工程上的松快時間拉長了看比查詢快幾秒值錢。往后單機寫入真到了天花板還有分布式超表這條路寫入再橫向攤一層架構不用推倒重來。先寫到這等真跑起來了再補后話。