第9期:報表應用的三層結(jié)構(gòu)
在傳統(tǒng)的報表應用結(jié)構(gòu)中,報表工具一般都是與數(shù)據(jù)源直接連接,并沒有一個中間的數(shù)據(jù)計算層。確實,大部分情況下的報表開發(fā)并不需要這一層,相關(guān)的數(shù)據(jù)計算在數(shù)據(jù)源和呈現(xiàn)環(huán)節(jié)分別處理就夠了。不過,在開發(fā)過程中,我們發(fā)現(xiàn),有一部分報表的計算即不適合在數(shù)據(jù)源也不適合在呈現(xiàn)環(huán)節(jié)實現(xiàn),這類報表在數(shù)量上并不占多數(shù),但耗用的開發(fā)工作量占比卻很大。
有過程的計算
報表工具都可以完成計算列、分組排序等運算,有些報表工具還提供了跨行組運算和相對格與集合的引用方案,可以完成頗為復雜的運算。
不過,報表工具中的運算是一種狀態(tài)式的計算,也就是把所有計算表達式寫在報表布局中,根據(jù)依賴關(guān)系自動處理計算次序。這種方法很直觀,在依賴關(guān)系不太復雜時能一目了然地了解各單元格的運算目標。但是,在依賴關(guān)系較為復雜,數(shù)據(jù)準備計算需要分成多步時,狀態(tài)式計算就困難了。如果一定要在報表中實施過程式計算,常常需要借用隱藏格,而隱藏格不僅將破壞狀態(tài)式運算的直觀性,還會占用更多不必要的內(nèi)存。
比如要列出銷售額占前一半的大客戶,如果不借助數(shù)據(jù)準備環(huán)節(jié),就要在報表中使用隱藏行列手段將不該列出來的條目隱藏,而不能直接過濾掉。再比如帶明細的分組報表要按匯總值排序,需要先分組后排序,許多報表工具無法控制這個次序。
還有個典型例子是舍位平衡,明細值四舍五入后再合計,可能會與合計值的四舍五入值不相等,會造成了報表上明細與合計數(shù)值不一致,需要根據(jù)合計的舍入值倒推明細的舍入值,這種計算的邏輯并不復雜,但即便用了隱藏格也難以由報表工具完成。
多樣性數(shù)據(jù)源
與多年前的單一數(shù)據(jù)源不同,現(xiàn)在有許多報表的數(shù)據(jù)源并不只來源于關(guān)系數(shù)據(jù)庫,還可能是NoSQL數(shù)據(jù)庫、本地文件、從WEB上傳來的數(shù)據(jù)等。這些非關(guān)系數(shù)據(jù)庫的數(shù)據(jù)源缺乏標準的數(shù)據(jù)獲取接口和語法,有些甚至沒有最基本的過濾能力。而計算報表時總還要進行一些過濾甚至關(guān)聯(lián)運算,雖然報表工具一般都能提供這些計算能力,但由于都是內(nèi)存計算,只適合于數(shù)據(jù)量較小的情況,數(shù)據(jù)量較大時就會導致容量負擔過重。而且,大多數(shù)報表工具也不能很好地處理像json或XML這種多層數(shù)據(jù),也沒有靈活編碼能力以登錄遠程WEB服務獲取數(shù)據(jù)。
動態(tài)數(shù)據(jù)源也是常見的需求,報表工具使用的數(shù)據(jù)源一般事先配置好的,不能根據(jù)參數(shù)動態(tài)選擇,直接使用報表工具無法實現(xiàn)。報表被用于通用查詢時,取數(shù)用的SQL不能簡單地用參數(shù)控制條件,而經(jīng)??赡芤鎿Q某個子句,有些報表工具支持宏替換,能夠一定程度地解決這個問題,但根據(jù)參數(shù)計算宏值也是個有條件和過程的運算,直接在報表工具中很難完成。
性能優(yōu)化問題
我們在往期的文章中曾談到過,大多數(shù)情況的報表性能問題都需要在數(shù)據(jù)準備階段來解決,其中有許多場景都不能在數(shù)據(jù)源內(nèi)部處理。比如并行取數(shù)本來就是解決數(shù)據(jù)源IO性能問題,只能在數(shù)據(jù)源外部實現(xiàn);可控緩存需要在外存寫入緩存信息,也不能在數(shù)據(jù)源內(nèi)部處理;清單列表中的異步數(shù)據(jù)緩存和按頁取數(shù)的功能,都不是數(shù)據(jù)源本身提供的能力;即使可以在數(shù)據(jù)源環(huán)節(jié)處理的多數(shù)據(jù)集關(guān)聯(lián)問題,在多數(shù)據(jù)庫或非數(shù)據(jù)的場景、以及希望減輕數(shù)據(jù)庫負擔時,仍然需要在數(shù)據(jù)源外部解決。這些無法在數(shù)據(jù)源內(nèi)部處理的場景,顯然也無法在報表環(huán)節(jié)處理。
數(shù)據(jù)計算層
如果把傳統(tǒng)報表應用結(jié)構(gòu)的兩層改成三層,增加一個中間的數(shù)據(jù)計算層,這些問題就容易解決了。
上述的各種運算都可以在數(shù)據(jù)計算層實現(xiàn),報表工具只解決呈現(xiàn)問題以及少量適合狀態(tài)式的直觀計算即可。
其實,傳統(tǒng)報表應用結(jié)構(gòu)雖然沒有刻意強調(diào)數(shù)據(jù)計算層,但仍然有這一層,只是比較隱蔽。典型的實現(xiàn)手段就是使用數(shù)據(jù)源中的存儲過程或者在應用中使用報表工具的自定義數(shù)據(jù)源接口。存儲過程能夠解決一些過程式計算和性能優(yōu)化問題,但它只能應用于單個數(shù)據(jù)庫中,相當于在數(shù)據(jù)源內(nèi)部的處理,對于必須在數(shù)據(jù)源外處理的場景無能為力,有較大的局限性。自定義數(shù)據(jù)源則在理論上可以解決上述所有問題,而且?guī)缀跛袌蟊砉ぞ叨继峁┯羞@個接口,所以這種方式的應用更為廣泛。
那么,使用報表工具的自定義數(shù)據(jù)源是否就可以方便地實現(xiàn)數(shù)據(jù)計算層呢?我們將在下一期討論。