(感謝這篇文章對于 SO 來說可能太高級或太哲學了,我正處于架構規劃階段并尋求一些指導)
在使用我們的生產資料庫的克隆進行分析遇到一些困難之后,我嘗試定義一個事件事實表以及一些維度表,以使分析作業更簡單。
我在計劃中遇到的障礙是這個。我們有不同類別的事件,需要用不同的維度來描述它們。例如,假設我們有“帳戶設定”事件類別以及“畫廊”事件。
在事實表中,我可能有一個欄位 eventCategory 和 eventName,其中包含上面的示例值,例如:
'EventCategory': 'Account Settings'
'EventName': 'Update Card Billing Details'
或者:
'EventCategory': 'Gallery'
'EventName': 'Create New Gallery'
在每種情況下,我都想使用不同的維度集合來描述它們。例如,對于畫廊活動,我們想知道“模板”、“影像數量”、“畫廊類別,例如水果”。我們不需要帳戶設定事件的這些詳細資訊,它們有自己獨特的一組維度來描述它們。
通過我在網上找到的教科書示例,我將有一個用于畫廊事件的維度表和一個用于帳戶設定事件的維度表。
我的心理障礙是這些維度是動態的而不是靜態的。我想在事實表中記錄事件發生時這些維度的值,而不是“現在”。例如,用戶可以是試用用戶,也可以是付費用戶。如果我有一個維度表“用戶”,他們的狀態目前可能是“已付費”,但在之前的一些畫廊活動中,他們可能已經在試用中。
處理此問題的“正確”方法是什么:
- 多個事實表,一個用于畫廊事件,另一個用于帳戶設定事件?
- 在主事實表的新欄位中使用 json,例如“EventDetail”,它包含否則會出現在維度表中的內容,除非使用 json 我們知道事件發生時維度的值,而不是現在這些值?
- 我可以有一個稀疏的事實表。我將包括所有類別中每個維度的欄位,如果不適用,這些欄位將為空
鑒于我用來描述事件的維度是動態的,構建用于分析的事實表的“正確”方法是什么?我剛才看到的方式維度表本身必須是事實,以捕獲這些屬性隨時間變化的值。
uj5u.com熱心網友回復:
向任何 SQL 表添加維度總是以相同的方式完成,即添加一列。
在任何一種歷史中,都沒有“現在”。每個狀態都有一個時間段:開始和結束。我通常將這些列命名為AsOfand Until,因為 begin/end經常作為 SQL 關鍵字出現,這使得列名更難掃描。通常,只AsOf需要,因為您可以自連接表以查找后續期間,并使用 NULL 表示“現在”(其中“現在”的意思是執行查詢的時間)。
“用戶”他們的狀態目前可能是“付費”,但在之前的一些畫廊活動中,他們可能已經在試用中。
是的,所以用戶的狀態不僅僅是付費/試用。它是付費或試用的,從某個日期的 AsOf 開始,直到同一用戶的較晚的 AsOf 日期。
很難提供更多幫助。您的問題中有一些行話,而且是用特定領域的術語表述的。我希望通過為每個狀態附加日期/時間,您可以看到走出森林的路。
uj5u.com熱心網友回復:
(A) 在 postgres 中管理時態資料
時態資料是多種業務應用程式中非常常見的需求,但它不是 postgres 中的“內置”功能,也不是許多其他 RDBMS。
正如@James K. Lowden 所述,您可以使用一些帶或不帶時區的AsOfandUntil型別的列timestamp,或者您可以使用tsrangeor型別的單個列tstzrange,即一系列時間戳,這將為您提供一些不錯的內置 -在功能方面,請參見手冊。
為了避免與相同資料的不同事件關聯的時間戳范圍之間的重疊,您可以使用觸發器函式實作業務邏輯。例如,對于同一用戶,您可以實作以下觸發器函式,以便在相應的行插入時自動設定與“試用”狀態相關聯的范圍 r1 和與“已付款”狀態相關聯的范圍 r2user表,并相應地更新同一用戶的現有行的范圍:
CREATE OR REPLACE FUNCTION before_insert_user ()
RETURNS trigger LANGUAGE plpgsql AS
$$
BEGIN
-- update all the existing rows (ie status) for the same user_id whose valid_ranges are valid as of now
UPDATE user
SET valid_range = tstzrange(lower(valid_range), Now())
WHERE user_id = NEW.user_id
AND valid_range @> Now() ;
-- set up the valid_range for the new row (ie the new status)
NEW.valid_range = tstzrange(Now(), NULL) ;
END ;
$$ ;
CREATE OR REPLACE TRIGGER before_insert_user BEFORE INSERT ON user
FOR EACH ROW EXECUTE FUNCTION before_insert_user () ;
(B) 管理不同類別的不同維度
正如已經討論過的,json可以是在同一列中存盤各種維度的解決方案。
另一個解決方案可能是具有一些有趣功能的表繼承:
CREATE TABLE Event
( EventCategory varchar
, EventName varchar
, ValidityRange tstzrange
, primary key (EventCategory , EventName, ValidityRange )
) ;
CREATE TABLE user
( status varchar
) INHERITS Event ;
CREATE TABLE Gallery
( template varchar
, "count of images" integer
, "gallery category e.g. fruits" varchar
) INHERITS Event ;
uj5u.com熱心網友回復:
事實表需要定義其粒度;如果事實與該粒度不匹配,則它們無法存盤在該事實表中 => 如果您有不同集合的事實,如果維度,那么您需要使用不同的事實表。
關于維度變化中的值,您需要閱讀緩慢變化的維度
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/380151.html
標籤:sql PostgreSQL的 数据库设计 事实
