在高度系統化驅動的業務中,查看業務報表已經是一個很常見的需求了。在分工非常明確的大型企業里,往往有專門的數據分析團隊 BI 或者數據開發團隊,他們能夠勝任此類需求(但也未必是輕松的,或者說高效的)。
但是,在都是業務開發的中小團隊中,業務報表需求,往往就是業務系統的程序員自己進行開發。我不知道這種情況有多普遍,至少在我自己的團隊是這樣的。業務系統的設計往往是為了實現更強一致性,更高效率,而設計數據庫的數據結構。而在這基礎上進行報表開發,往往會寫出非常復雜的 SQL。
而不同角色的管理者,要求的不同分析視角,使得報表的復用性無法達到理想的程度。開發繁復的報表統計需求,成為了程序員一個無法避免的負擔。而在一個“管理信息”集中的系統里,這種矛盾變得尤為凸顯。不光是實現這樣的需求變得困難和不堪重負,僅僅是保持實現的正確性和高效性,都變得極為困難。
引入大寬表,可以有效降低開發的難度,以及提升代碼的復用性。
一、什么是大寬表?
大寬表,顧名思義是一種由單一 key 聚合起來的大量的相關列數據。舉個簡單的例子,以用戶的 ID 為 key,把跟用戶相關的所有字段,全部提取出來放到一個單一的表里,每個字段一列,這種就是一個大寬表。
大寬表,我相信這個概念在數據倉庫里非常普遍,我也就借由數據倉庫的一些基本概念來闡述大寬表的概念。
1. 數據倉庫
數據倉庫的概念就像表面上的意思,是數據的倉庫。不那么顯然的是,數據倉庫的存在,往往是為了數據分析的需要,也就是我們常說的 OLAP。而業務生產系統往往是為了事務的需求,也就是我們常說的 OLTP 系統,這恐怕也是相對于數據倉庫來說的。
將數據從多種不同的業務系統提取,并進行整理后,產生以適應多維度分析的數據結構和格式,是數據倉庫這個關鍵性系統的重要任務之一。
我兩度經手管理跟大數據有關的團隊,都會看到一個經典的結構圖,關于數據倉庫的一般性架構的:
每次我看到圖的時候都是一頭霧水的:
- ODS(Operational Data Store)原始數據,業務庫表
- DWD(Data Warehouse Detail)原始數據經過清洗
- DWS(Data Warehouse Summary)大寬表
- DM(Data Market/ Marts)數據集市
- ADS(Application Data Service)應用數據服務
我根本不知道什么意思。括號里寫的一些縮寫,也只是我網上隨便找的,未必就是精確的,至少每個大數據開發,架構師都一套振振有詞,雖然他們也未必能說清楚縮寫的真實含義。
回來,不管數據倉庫到底是什么意思,但是都透露出一個基本的思想,就是業務數據需要經過整理和規范化處理,然后,形成按照特定主題聚合的“成品”數據,方便分析應用更好的使用。
2. 無奈的選擇
如果你所在的公司,有一個建制完善的大數據開發團隊和對應的數據分析團隊,那么恭喜你,你可以從這類的任務中擺脫出來,專注于業務邏輯的開發。否則,應對各種各樣的報表需求,也是你不得不接受的任務。
大數據的架構看似美好,但是就跟 OSI 的網絡七層模型一樣,這是理論中完美,在實操過程中,要應對各式各樣的挑戰。這也就是我在文章開頭說的,即便對于專業的大數據開發團隊來說,實現數倉的架構既不是輕松的,也不是高效的。
不過,我在實際業務執行過程中體會到,數據倉庫的思想是非常先進的,也有很多的可取之處。比如,根據一個用戶的 ID,就可以提取到有關此用戶單個人的所有統計信息,然今后再進行簡單的聚合,就可以計算出各種想要的分析維度,這難道不美好么?與之相對的,你可能要在系統里聯表七八張,然后用復雜的過濾條件,再用復雜的 Group By,最后得到的數據,還需要在代碼層再次進行運算,才能得到結果。
數據倉庫的數據分層清洗匯總的思想,將很多復雜的運算,在計算層次上進行了抽象和分離,最終實現了計算和統計分離,是一種高效的解耦思想。
我們的所有統計分析在一條復雜 SQL 中出來,這種反倒是將所有東西雜糅在一段代碼里進行處理,一個是不方便復用(只能拷貝過去改改),另一個就是不方便調試(很難閱讀,也很難比較)。
但是我們又沒有足夠的人力去把整個數據倉庫做出來,形成一個四層結構的 DW。那么這時候,大寬表,就是我們妥協后的一個很好選擇,也會成為未來數據倉庫構建的一個良好基礎。
二、如何設計大寬表
大寬表,實質上,就是一個結構復雜的業務數據表集合,根據單一 key 在二維上一種展開格式。舉個例子,用戶大寬表,包含 ID,姓名,賬號,注冊日期,訂單數,消費次數,消費總金額,消費平均間隔,消費最高的五個品類,消費的價格區間,等等等各種簡單但并不平凡的字段構成。
有了這張寬表,我們可以分析用戶的消費能力,消費習慣,活躍程度,流失概率等等各種報表。
1. 歸納法
你的團隊應對單個分析需求的時候,往往不會想到要去做個大寬表,因為單個分析需求來的時候,業務往往剛剛起量,我們不可能遇見未來的發展趨勢,一般都是直接幫需求方實現了。
但是當類似的需求越來越多的時候,就要警醒,可能業務已經進入騰飛的態勢,未來此類分析會越來越多,越來越頻繁,而我們需要提供精度越來越高的數據。
這時候,將已經收到并實現過的統計分析需求,進行匯總觀察,提煉一個主要的分析 key,并形成寬表設計,就是一個明智的選擇。這種方法,我稱為歸納法。
2. 字段遴選
哪些字段進入大寬表,哪些不要,這是一個艱難的選擇題,我們業務團隊自行研發寬表,本來就是一個不得已的選擇,意味著我們開發的資源非常有限。不可能無限實現各種字段。
那些明顯能夠支撐統計需求的字段,必然納入我們的選擇,哪怕是冗余的。這些統計字段都會降低后期分析報表出具的難度。但是有些變化不那么頻繁的字段,也可以繼續保留主鍵,而不對值進行展開,這就意味著后期分析的時候,仍然需要聯表查詢,在數據倉庫中,這種往往叫維度表,但是哪些字段可以作為維度表,并不是表面上那么明顯,經常是艱難的抉擇,這就需要長期業務開發積累的經驗。
三、缺點和困難
說了很多優點,缺點和難點卻不得不提。
比如,一致性和延遲
就是一個最大的問題。客戶是不會容忍你,多少分鐘同步一次的。他們只覺得,我在系統里改了數據,我的統計值為什么不變?解決這個問題,就要做好事先需求的溝通和用戶教育,對用戶做出延遲承諾,比如,XX 數據,在變更后,至多 10 分鐘完成各種環境的同步,這就是一種服務承諾。通過這樣的方法,在用戶心中建立合理的預期。
第二,寬表構建的 依賴和調度的復雜度
。比如寬表里的字段,有些在構建時期,就是通過多個關系表,關聯起來以后綜合計算或者說判斷的,在寬表里表達很簡單,只是一個字段而已,但是計算過程可能就比較麻煩,有著前后依賴。我舉個例子,比如我們用的一個金額列,必須先計算當地支付金額,然后在這個基礎上,查詢貨幣兌換的比值(需要用幣種和發生時間查表得到),進行外幣折算后,才能成為一個有效的金額字段。在進行此類字段的構建時,就出現了依賴的問題,我先要構建第一個字段,然后查詢其匯率,才能構建第二個字段。構建時候需要先計算原始幣種,發生時間,然后下一步驟才能計算折算金額,有前后依賴問題。
另一個自然想到的問題,是一旦業務數據庫發生了變化,這種前后依賴的數據計算,還需要被及時和順序地調度,這就引發了需要一個強大的依賴管理和任務調度系統。才能有效實現數據寬表的及時更新。