蒼時弦也
蒼時弦也
資深軟體工程師
發表於

報表機制 - 重新思考 Rails 架構

這篇文章是 重新思考 Rails 架構 系列的一部分。

報表功能也是非常常見的情境,大多數時候我們都會直接使用 Rails 的資料庫內容,搭配 JOIN 類型的查詢進行處理,然而這並不總是個好辦法。

減少重複

在工程師學習的經驗中,我們很常會聽到 Reuse(重用)的概念,也盡力的在開發過程中進行實踐,資料表正規劃也是類似的概念,我們都在嘗試減少「重複」

在正確的情境下進行這樣的處理並沒有問題,然而我們也很常誤用這樣的概念,最後造成實作有嚴重的耦合,逐漸走向難以維護的困境。

實際上,一定程度的重複是可以被接受的。我們會想減少重複是希望有「Single source of truth(SSOT)」的效果,假設只有一個資料來源就不容易出錯。

然而,在較大跟複雜的系統,如果我們要加快業務(Transaction)的處理的速度勢必要放棄「短時間」內的一致性,以最終一致性(Eventual consistency)為目標,那就有可能需要將同樣的資料複製給不同節點「並行」的進行處理。

OLAP & OLTP

大多數時候使用 Rails 開發的都是 OLTP(線上交易處理)類型的任務,然而報表是屬於 OLAP(線上分析處理)的範疇。

舉例來說,我們想要對某個商品下單,可能會需要快速的將商品資訊、使用者資訊等等組合處理,最後給出是否可以下單的情境。然而,如果是要分析某個使用者過去一年的交易行為,將這些資料組合起來的成本是非常高的,假設能夠在一張資料表就取得所有的資料一次做比較,那就相對的容易。

以 PostgreSQL 來說,就有提供 Materialized View 的機制,可以定期對特定的 SQL 查詢結果保存起來,用於後續的資料分析。

假設我們希望使用者可以快速的進行交易,又需要可以讓這個系統能夠分析使用者的行為,我們可能會有兩種不同職責的資料表(或不同資料庫)保存重複的內容。因此,資料庫的正規化與否,以及是否要消除重複,會根據應用的情境而改變。

當時我們耗費大量力氣製作複雜的 SQL 來滿足查詢需求,仍然很慢的情況下,客戶才接受搭建另一個資料庫專職負責報表的機制,用於緩解查詢緩慢以及難以維護的狀況。

客製化報表

除了上述的查詢問題外,客製化報表也是一個非常大的挑戰。因為每個人想看到,或者需要看到的內容是不同的,因此會需要設定他們想要的呈現方式。

假設是以 OLTP 的方式來處理,我們就需要動態的去組合出所需的 SQL 查詢在不同資料表取得資料,並且根據使用者的設定呈現出期望的報表內容。

然而,大多數情況是針對某種「標準」的報表,隱藏掉不必要的欄位只留下必要的內容進行呈現,這也對應到 OLAP 的特性,我們所需處理的通常會是隱藏欄位跟合併多列資料進行呈現,如此一來在報表的產生上也變得容易不少。