關系型數(shù)據(jù)庫存儲多維指標數(shù)據(jù)
什么是多維指標數(shù)據(jù)?
指標是一個統(tǒng)稱概念,可以細分為 原子指標? 和 派生指標 。 以 某企業(yè)近一周上海地域的銷售金額 為例,整體是一個派生指標,其中的 銷售金額 是原子指標; 近一周 是時間, 企業(yè) 和 地域 是維度。
可見,指標數(shù)據(jù)由三部分組成:
- 時間
- 維度
- 數(shù)值
其中,維度可以是一個或多個,也可以是零個,簡稱為多維。
什么是關系型數(shù)據(jù)庫?
典型的關系型數(shù)據(jù)庫就是 MySQL 。
使用時,需要先根據(jù)業(yè)務設計好數(shù)據(jù)模式:
- 數(shù)據(jù)庫中有哪些數(shù)據(jù)表
- 數(shù)據(jù)表中有哪些字段
然后,創(chuàng)建相應的數(shù)據(jù)庫和數(shù)據(jù)表;最后,存儲業(yè)務數(shù)據(jù)。
關系型數(shù)據(jù)庫會有一個特殊的約定 :數(shù)據(jù)模式是相對固定的。業(yè)務不發(fā)生變化的情況下,數(shù)據(jù)模式不會輕易發(fā)生變化。
使用關系型數(shù)據(jù)庫存儲多維指標數(shù)據(jù)會有什么問題?
不同的業(yè)務會有不同的指標,每一個業(yè)務可以單獨創(chuàng)建一個數(shù)據(jù)庫,這個比較好理解。
每一個指標都會有時間和數(shù)值,但是不同的指標之間,它們的維度名稱和維度數(shù)目卻可能是不同的。
最直接的設計:
- 每一個指標單獨創(chuàng)建一個數(shù)據(jù)表,位于某個業(yè)務數(shù)據(jù)庫
- 數(shù)據(jù)表除時間和數(shù)值字段外,根據(jù)指標的不同,創(chuàng)建若干維度字段
假設某個指標有三個維度:a、b 和 c,表結(jié)構如下所示:
timestamp | a | b | c | value |
2022-09-15 00:00:00 | a1 | b1 | c1 | 1 |
2022-09-15 01:00:00 | a2 | b2 | c2 | 2 |
2022-09-15 02:00:00 | a3 | b3 | c3 | 3 |
timestamp 表示時間,value 表示數(shù)值,a、b 和 c 表示維度。
問題很明顯:
- 如果某個業(yè)務擁有成千上萬個指標,就需要創(chuàng)建成千上萬個數(shù)據(jù)表。無論是預先創(chuàng)建數(shù)據(jù)表,還是隨著指標的新增動態(tài)創(chuàng)建新的數(shù)據(jù)表,如此數(shù)目龐大的數(shù)據(jù)表是不能接受的。
- 固化的數(shù)據(jù)表結(jié)構不能很好地應對指標的維度名稱和維度數(shù)目發(fā)生變化的場景。
受限于業(yè)務方的部署環(huán)境,僅支持關系型數(shù)據(jù)庫 MySQL;而且業(yè)務方不能接收一個業(yè)務指標一個數(shù)據(jù)表的粗暴設計。
思考
業(yè)務指標的數(shù)目是不可控的,但業(yè)務指標的維度數(shù)目是相對可控的,我們是否可以按維度數(shù)目創(chuàng)建 指標表 ,畢竟絕大多數(shù)數(shù)據(jù)可視化組件最多支持三維。
比如:
- 維度數(shù)目為 0 的指標表
- 維度數(shù)目為 1 的指標表
- 維度數(shù)目為 2 的指標表
- ...
假設維度數(shù)目為 3 的指標表,表結(jié)構如下所示:
id | timestamp | d1 | d2 | d3 | value |
m1 | 2022-09-15 00:00:00 | a1 | b1 | c1 | 1 |
m2 | 2022-09-15 01:00:00 | a2 | b2 | c2 | 2 |
m3 | 2022-09-15 02:00:00 | a3 | b3 | c3 | 3 |
id 表示指標 ID,用于唯一標識指標;d1 、d2 和 d3 分別表示維度1、維度2 和 維度3。
一張數(shù)據(jù)表中可以存儲多個相同維度數(shù)目指標的數(shù)據(jù),如:m1、m2 和 m3。存儲指標數(shù)據(jù)時,只要按指標的維度數(shù)目,將指標數(shù)據(jù)存儲到相應維度數(shù)目的指標表中即可。指標表可以根據(jù)業(yè)務可能的最大維度數(shù)目預先創(chuàng)建,業(yè)務維度數(shù)目需要擴展時,僅需要新增有限的幾張?zhí)囟ňS度數(shù)目的指標表即可。
還不夠!
指標有維度的情況下,指標表僅支持按指標維度次序,依次存儲和查詢維度1、維度2、... 的維度數(shù)據(jù),并不知道具體的維度名稱是什么。
考慮到業(yè)務希望指標發(fā)生變化時,歷史數(shù)據(jù)可追溯,同一個指標需要有多個版本。
也就是說,我們需要知道:
- 指標的版本有哪些
- 指標的某個版本有哪些維度,維度名稱是什么
- 指標的某個版本有哪些數(shù)據(jù)
我們可以:
- 創(chuàng)建一張版本表,存儲指標有哪些版本
- 創(chuàng)建一張維度表,存儲指標的某個版本有哪些維度(名稱)
- 根據(jù)維度數(shù)目創(chuàng)建若干張指標表,存儲指標的某個版本的指標數(shù)據(jù)
可行!
存儲方案
版本表
id | version |
m1 | 1 |
m2 | 1 |
m1 | 3 |
id 表示指標 ID,version 表示版本號。
版本表存儲著指標和版本的對應關系,可以查詢指標的歷史版本記錄,也可以查詢指標的最新版本。
維度表
id | version | name |
m1 | 3 | a1 |
m1 | 3 | a2 |
m1 | 3 | a3 |
id 表示指標 ID,version 表示版本號,name 表示維度名稱。
維度表存儲著指標/版本和維度名稱的對應關系,可以按指標 ID 和指標版本查詢維度名稱列表,多個維度名稱的順序按維度名稱存儲順序依次排列。
指標表
id | version | timestamp | d1 | d2 | d3 | value |
m1 | 3 | 2022-09-15 00:00:00 | a1 | b1 | c1 | 1 |
m1 | 3 | 2022-09-15 01:00:00 | a2 | b2 | c2 | 2 |
m1 | 3 | 2022-09-15 02:00:00 | a3 | b3 | c3 | 3 |
指標表存儲著指標數(shù)據(jù)。注意,維度1、維度2 和 維度 N 的表現(xiàn)形式。
存儲指標數(shù)據(jù)
新增指標時,使用 Unix 時間戳作為版本號,存儲指標 ID 和 版本至版本表;如果指標有維度,存儲指標ID、版本號 和維度名稱至維度表,如果維度有多個,需要按照維度排列順序依次存儲多條記錄。
修改指標時,如果修改后的指標維度名稱列表和維度表中該指標最新版本的維度名稱列表數(shù)目或內(nèi)容不一致,需要和新增指標一樣,存儲該指標新的版本號和維度名稱列表。
存儲指標數(shù)據(jù)時,獲取維度表中該指標最新版本的維度名稱列表,即可知指標維度數(shù)目;根據(jù)維度數(shù)目選取指標表,將指標數(shù)據(jù)存儲至該指標表,維度名稱需按順序依次存儲至維度1、維度2、...。
查詢指標數(shù)據(jù)
- 根據(jù)指標 ID 查詢版本表,獲取該指標的最新版本號,或者直接指定某個版本號;
- 根據(jù)指標 ID 和版本號,查詢維度表,獲取該指標的維度名稱列表和維度數(shù)目;
- 根據(jù)指標的維度數(shù)目,選取指標表;
- 根據(jù)指標 ID 和版本號,查詢指標表,獲取該指標的數(shù)據(jù);也可以使用時間或維度過濾指標數(shù)據(jù)。
- 使用 2 中獲取指標的維度名稱,替換 4 中獲取的指標數(shù)據(jù)中的維度1(d1)、維度2(d2) 、...。