資料準備 ——報表開發中的深層次問題

xiaohuihui發表於2020-07-05

前言

現在企業的報表開發大部分都使用報表工具完成,成熟的報表工具提供了豐富的顯示設定、圖表型別、匯出列印等功能可以簡化報表開發,非常方便。但在實際報表開發中還是經常碰到一些非常棘手的深層次問題,即使是已經熟練使用報表工具的開發老手也會很撓頭。

為什麼有了報表工具還會出現這些問題呢?

報表開發,看起來就是將資料按照指定格式的表格或圖形呈現出來,這也是報表工具一直以來很擅長的環節。但是,原始資料經常並不適合直接呈現,需要先做一些複雜的處理,這就是資料準備環節。

從報表工具的眼光上看,資料準備屬於報表之外的事情,可以堂而皇之地拒絕處理。但是,拒絕不等於不存在,這個工作總還要做。沒有好的工具,目前報表的資料準備還處於比較原始的硬編碼階段,上千行的 SQL、幾百 K 的儲存過程和大量的 JAVA 程式碼充斥在報表之後。

落後的工具必然導致低下的生產效率,會嚴重拖累整個報表開發的程式,也就出現了前述的“撓頭”現象。再由於大多數報表工具的不重視,這個問題遲遲還沒有被解決的跡象。

報表資料準備之於報表有如樹根之於大樹,如果根本得不到解決,在枝葉上花多少精力都是白費。

這種深層次問題在報表開發初期一般很少碰到,但隨著報表開發的深入這些問題會接連不斷地出現了。

我們在這裡收集整理了一批此類問題,以供報表開發者參考。內容比較多,建議先收藏再慢慢看。

目錄

1. 零編碼製作報表可能嗎?

要回答這個問題,首先要明確啥程度算“零編碼”?
以 Excel 為例,如果把寫 Excel 公式(包括複雜一些的)看做零編碼;而把寫 Excel VBA 看做編碼的話,

報表開發是可以零編碼的!

但是,這有個前提:在資料(集)準備好的情況下才可以零編碼!

為什麼這麼說?
我們知道報表開發主要分兩個階段:
第一階段是為報表準備資料,也就是把原始資料透過 SQL/ 儲存過程加工成資料集;
第二階段是使用已準備的資料編寫表示式做報表呈現。在報表工具提供的 IDE 裡視覺化地畫出報表樣式,然後再填入一些把資料和單元格繫結的表示式就可以完成報表呈現了,雖然表示式可能比較複雜,但相對硬編碼要簡單得多(Excel 公式和 VBA 的關係)。所以說這個階段是能做到“零編碼”的。

資料準備 ——報表開發中的深層次問題

那報表資料準備怎麼辦?
很遺憾,這個階段沒法零編碼,一直以來只能硬編碼,想想我們報表裡寫的巢狀 SQL、儲存過程、JAVA 程式就知道了。為什麼報表工具發展這麼多年報表呈現已經完全工具化而報表資料準備的手段還這樣原始呢?因為這個階段太複雜了,不僅涉及計算邏輯的演算法實現,還涉及報表效能(要知道大部分報表效能問題都是資料準備階段引起的)。

那報表資料準備是不是沒辦法了呢?
雖然不能做到零編碼,但可以朝著簡單化的方向努力,將資料準備階段也工具化,這樣可以使用工具提供的便利來簡化報表資料準備階段的工作,從而進一步簡化報表的開發。

那怎麼實現報表資料準備工具化?
要實現這個目標並不容易,像上面提到要考慮的內容有點多,大體來說資料準備工具至少要滿足這幾方面:
1. 具備完備的計算能力
說的有點拗口,掰開了其實在說既然在工具裡做資料計算,那得讓我什麼都能算吧,不能原來 SQL/JAVA 寫的放到這裡就不行了,該有的計算方法和類庫都應該有,最好用起來還比較簡單(比原來硬編碼難就沒意義了),專業的說法叫:計算體系是完備的;

2. 支援熱切換
這點是相對 JAVA 來說的,透過資料準備工具生成的演算法應該是解釋執行的,不能每次改完報表還要重啟應用,即時修改即時生效;

3. 具備多源混算能力
透過資料準備工具可以同時連線多種資料來源(RDBMS、NoSQL、TXT、Excel、Hadoop、HTTP、ES、Kafka 等等)進行計算,混合計算,這個資料來源讀個表、那個資料來源載入個檔案,兩部分資料可以 join 到一起混算。現在我們的資料來源太多了,報表常常會跨資料來源取數,支援了異構源混算以後,原來還要考慮諸如資料是不是先入到一個庫裡的事情就不用管了,那叫一個清爽;

4. 高效能
直接簡化資料準備的工作還不夠,實現再簡單跑不快也不行。所以,還要高效能,至少不能比原來跑的慢吧,大家都是講道理的人;

以上是我們認為資料準備工具應該具備的能力,其他還有一些能力不是特別重要,但如果有最好了。包括:
* 有沒有易用的編輯除錯環境,可以很方便地除錯演算法;
* 為了更快能不能平行計算
* 有沒有標準介面可以讓其他程式或工具呼叫
等等,實際要用的時候照著這些特點去找就行了,有益無害。

說了這麼多,總結來說,“零編碼製作報表”的確更像一句口號,沒法真正做到,但可以不斷努力接近這個目標,求其上得其中嘛。

擴充套件閱讀:


2. 為什麼說當前報表開發的工作量主要在資料來源環節?

我們知道,報表開發主要有兩個階段。
第一階段:資料準備。將原始資料加工成報表需要的結果集(資料來源);
第二階段:資料呈現。根據已準備的結果集(資料來源)編寫表示式將資料以表格或圖形方式呈現。

這兩個階段雖然處於同一報表開發過程,但實現方式卻大不相同。

通常原始資料距離報表“能用”還相去甚遠,透過 SQL/JAVA/ 儲存過程等編碼方式準備報表可用的資料來源是第一階段的目標,過程中可能涉及複雜的資料處理過程,因而這個階段會牽扯較多的精力,佔用的工作量也多。

資料來源準備好後,透過報表工具來解決資料以何種方式(圖表)、何種樣式(外觀)呈現的問題,透過點選設定、編寫少量表示式就可以快速完成,實現簡單,佔用的工作量也少。

可以說,報表開發的工作量主要在資料處理(計算),資料處理後如何呈現,透過工具可以快速完成。

那是不是報表呈現階段就不涉及資料處理了呢?
並不完全是這樣。

早期報表開發
大概 2015 年以前,報表呈現方式主要以表格(或圖表混合)為主,這時透過報表工具實現時就會涉及一定的資料計算,如分組彙總、多源分片、格間計算(同比環比)等。如下圖所示:

資料準備 ——報表開發中的深層次問題

計算分佈在資料準備和資料呈現兩個階段,兩個階段的工作量相當(各佔 50%)。這個時期,資料準備階段可以把資料準備得“粗糙”一些,然後利用報表工具的計算能力在呈現階段將資料進一步加工成目標結果進行呈現。比如,我們在資料準備階段完成關聯過濾,再在報表呈現模板中按多個維度分組彙總;或者在呈現模板中計算同比環比。

當前報表開發
隨著報表工具的逐漸成熟,報表工具提供了更豐富的圖形(型別和效果),報表選擇圖形呈現幾乎與表格佔比相當了(佔比仍在增長)

資料準備 ——報表開發中的深層次問題

使用圖形呈現,由於沒有“格子”,就無法利用報表工具的計算能力在呈現模板中完成資料處理,而圖形本身並不具備計算能力(不包括硬編碼),這時自然而然就要在資料準備階段將前端需要的資料完全準備好,前端工具接收資料直接圖形呈現。
圖形設定基本沒什麼工作量,而後端資料來源的準備工作就佔了大頭,資料呈現和資料準備所佔的工作量佔比約為 20%:80%。

當前報表開發的工作量主要在資料來源端(資料準備階段),要提升報表開發效率,勢必要解決報表資料來源準備效率問題。這也是為什麼很多時候用上了一流的報表工具,但報表開發的工作量仍然很大的原因。

如何提升報表資料來源端的開發效率,從而整體降低報表開發工作量?

借鑑報表開發的發展歷史,或許可以獲得一些思路。
早期,報表開發靠完全硬編碼,無論資料準備還是報表呈現,後來報表工具出現替代了硬編碼方式,將報表呈現階段的開發工具化,解放了報表呈現階段的人力(你可以感受一下寫程式碼畫報表比用工具做麻煩多少)。

按照這個思路,用工具替代硬編碼就可以提高生產效率,將資料準備階段工具化就可以解決報表資料來源的開發效率,從而進一步提升報表整體開發效率。

資料準備 ——報表開發中的深層次問題

資料準備工具可以是獨立的,也可以包含在報表工具內部,後者要求報表工具的能力能夠延伸到資料來源層面。

擴充套件閱讀:

3. 用儲存過程和 JAVA 寫報表資料來源有什麼弊端?

我們在報表開發中經常會使用儲存過程準備資料,儲存過程支援分步計算,可以實現非常複雜的計算邏輯,為報表開發帶來便利。所以,報表開發中這樣的儲存過程並不少見:
資料準備 ——報表開發中的深層次問題

資料準備 ——報表開發中的深層次問題

3008 行,141KB 的儲存過程,會給報表開發帶來什麼不好的影響?

1. 編輯除錯性
儲存過程難以編輯除錯,這樣幾千行儲存過程的開發週期往往要以周或月計,這樣會嚴重影響報表的開發效率,而業務提的報表需求似乎都“很急”。

2. 維護性
相對開發的一次性,維護的工作可能要經常做。實際業務中報表經常會修改,這種現象叫做報表業務的穩定性差。報表的資料準備邏輯變化,修改上千行的儲存過程對絕大多數報表開發人員來說都是噩夢。

有時這樣的報表會分兩撥人來做,DBA 或專業程式設計師負責編寫儲存過程給前端報表開發人員做報表,這樣就避免了報表開發人員寫儲存過程。但這樣報表修改的流程會變長,修改一張報表涉及多個人員之間溝通(還包括業務人員),如果負責報表前後端的兩撥人隸屬不同的團隊就更麻煩了。

3. 知識傳承
從維護性可以直接引出另一個“知識傳承”的問題。還是拿上面的報表為例,如果一個新人要改上面的報表,你覺得他要多久能看懂儲存過程,改完報表?

當然,這個問題還涉及很多管理方面的手段,單純從技術本身來看,這樣的報表想要很好地傳承知識是很難的。

4. 安全性
對儲存過程的修改需要較高的資料庫許可權,而報表經常要改就要經常運算元據庫,這對資料庫安全也是一個隱患,同樣需要強管理機制才能保障一二。

5. 移植性
現在絕大多數規定禁止使用儲存過程的原因,首當其衝的就是儲存過程沒有移植性。如果未來資料庫發生變化需要遷移,不管將來是更換資料庫型別,還是系統擴充套件(分表分庫),大量無法移植的儲存過程絕對是最頭疼的問題。

當然,“換庫”這件事情即使在今天仍然不會頻繁發生,但是隻要發生一次就夠受了(有國產化或系統擴充套件預期的就要注意了)。

6. 耦合性
從維護性、安全性和移植性看來,儲存過程會導致報表應用(前端)和資料庫(後端)緊耦合。緊耦合除了會導致前面的三個問題外,還會讓資料庫編的臃腫,影響資料庫效能。

重要的事情說好多遍,報表的業務不穩定,報表除了經常增加和修改,有時還會刪除(不用了),而為這個報表準備的儲存過程還在資料庫裡,這時想要刪掉這個儲存過程就比較難了。

為什麼?

因為你不知道是不是還有其他程式在共用這個儲存過程,刪除會不會對其他程式產生影響。結果就是資料庫的儲存過程越積越多導致資料庫臃腫,而有的儲存過程還會涉及自動執行,雖然儲存過程可能不再使用,但仍然在消耗資料庫資源,長此以往資料庫效能下降就成為必然了。

7. 多源支援
儲存過程執行在封閉的資料庫內,無法進行跨多資料來源混合計算。關於多源問題,幾年前在報表開發還不顯著,那時大家都用關係庫;但現在不一樣了,同一個報表的資料可能來自多個不同型別的資料來源(RDB/NoSQL/TxT/Excel/Hadoop/ES 等等),這時儲存過程就無能為力了。

如何搞定這些問題?
有沒有辦法解決儲存過程帶來的這些問題呢?

當然有!

沒有什麼是硬編碼解決不了的!用 JAVA 替代儲存過程,脫離資料庫執行來解決上面的問題(自行搜尋 SOA 和微服務理念)。儲存過程一個顯示的好處是可以分步實現報表資料準備邏輯,這個優點 JAVA 也有,甚至比儲存過程更徹底,說句文縐縐的話:JAVA 的離散性更好。

只是 JAVA 寫起來比較麻煩,對於報表開發人員來講太難了,如果還要加一個修飾詞那就是太 XX 難了。儲存過程使用的 SQL 語言非常適合做集合運算,分組彙總一句 group by 就寫出來了,反觀 JAVA 就不具備這個優點了,分組彙總可能要寫上幾十上百行才行(類庫缺失會讓開發複雜度急劇上升,想想你為什麼不用匯編寫程式而要用 JAVA?)。

JAVA 還有一些其他的問題也不容忽視。

不支援熱切換
JAVA 還有一個非常致命的缺點,就是不支援熱切換。報表經常要改(又來一遍),修改報表資料來源以後還要重新編譯、重啟應用才能生效,對絕大多數業務系統都是不能接受的。報表講究的不僅是查詢立等可取,修改也要實時生效才行。

報表與應用緊耦合
與使用儲存過程會導致報表與資料庫緊耦合類似,用 JAVA 準備報表資料來源會導致報表模組和應用的其他業務模組緊耦合不宜維護。

我們知道,報表大多數情況都是作為一個模組整合到應用系統提供報表查詢服務,整合的方式可以是 API(jar 包)方式緊整合;也可以將報表單獨釋出成服務,透過服務呼叫的方式松整合,這樣報表伺服器產生的任何壓力或問題都不會影響應用系統(高可用)。*API 緊整合後,由於報表資料來源是 JAVA 寫的,這樣就要和主應用的程式碼一起打包,無法作為獨立的模組維護,而未來想要拆分也基本不可能了;* 服務松整合則完全無法實現。

所以,用 JAVA 寫報表資料來源雖然可行,但也不是特別理想。

那有沒有其他辦法呢?

我們比較一下儲存過程和 JAVA 的優缺點可以發現,解決問題應該是沿著繼承二者優點,改進缺點的方向進行。清晰起見,總結一下需要的點。

資料準備 ——報表開發中的深層次問題

把主要的點列了一下,我們的目標就是找到支援這些點的技術手段(問號所在行)。

易開發、易維護
這注定了這些能力應該是報表工具內建的,這樣報表開發人員自己就能使用工具搞定報表開發,而不必依賴其他人或團隊;

熱切換
熱切換要求這個技術應該是解釋執行的,這樣才能做到實時修改實時生效;

支援多源
能夠對接多種不同型別的資料來源進行混合計算,比如文字和資料庫表的 join;

低耦合、可移植
資料準備能力和報表呈現能力都報表內建了,自然與應用和資料來源都解耦了,未來系統擴充套件自然毫無壓力。

這樣我們可以很容易想到在報表端增加一個計算模組(或引入其他計算工具),來替代儲存過程或 JAVA 為報表準備資料,這個模組可以是由嵌入報表工具的指令碼來實現,結構可以是這樣的

資料準備 ——報表開發中的深層次問題

指令碼要具備完善的計算能力(什麼計算都能算),支援多源,解釋執行允許熱切換這些能力。

這才是報表工具的未來!

擴充套件閱讀:

4. 什麼是報表的多樣性資料來源問題?

在報表開發早期,報表連線的資料來源基本只有關聯式資料庫,而且經常只有一種或者只有一個資料庫。

但今天就不一樣了,資料來源種類繁多,除了 RDBMS 還有
1.MongoDB、Cassandra、HBase、Redis 這些 NoSQL 資料庫;
2.TXT/CSV、Excel、JSON/XML 等檔案;3.HDFS 等分散式檔案系統;
4.webService;
5.ES、Kafka 等其他資料來源形式
……

資料準備 ——報表開發中的深層次問題

當這些都成為報表資料來源,報表需要從這些資料來源分別或混合取數運算進行報表呈現時,報表就出現了多樣性資料來源問題。

具體是什麼樣的問題呢?

主要是兩個問題,複雜計算和多源關聯計算。

1. 複雜計算
我們知道,報表中的計算主要集中在兩處:

一處是資料準備階段。
透過 SQL/ 儲存過程 /Java 程式為報表準備資料,這個階段可能涉及非常複雜的資料處理邏輯。這樣, 計算能力尤其是集合計算能力較強的 SQL 就比較擅長了,透過 SQL、複雜 SQL 可以完成大部分的報表資料準備任務,有些涉及較多業務邏輯的計算還可以使用儲存過程,萬不得已時用 JAVA 自定義資料來源完成。

這是早期基於單一 RDBMS 開發報表時資料準備的常用手段,主要依靠 RDBMS(SQL)的計算能力來實現。

但這種方式在多樣性資料來源的場景下就行不通了,因為有的資料來源根本就不支援 SQL,甚至計算能力都比較弱(如 NoSQL),或者根本就沒有計算能力(如文字),這樣,資料準備計算計算無法在這個階段實現,就要看另外一處是否可以完成了?

二處是報表呈現階段
根據第一階段已準備的資料,在報表模板中填入繫結格子的報表表示式或圖形來呈現報表是使用報表工具開發報表的常用方式。這說明報表工具具備一定的計算能力,透過表示式可以實現分組彙總、過濾、排序,複雜一些的同比環比等計算。

但是,報表工具的計算能力是有限的。不考慮效能的情況下,單純從資料來源中讀取資料到報表呈現階段完成資料組織和報表呈現很多時候是做不到的,這也是為什麼我們會在資料準備階段進行復雜資料處理的原因了。

2. 多源關聯計算
與基於單一的某個資料來源進行的複雜計算不同,有時一個報表會同時連線多個資料來源,多個資料來源之間要混合計算,比如 MongoDB 的資料和 RDBMS 的資料關聯運算,文字和 Excel 關聯運算等。

這種跨異構資料來源的關聯無法直接透過資料來源自身的能力實現,只能藉助其他方法。


那報表的多樣性資料來源問題如何解決呢?

方法總比問題多。目前大家普遍採用兩種方式來解決報表多樣性資料來源的問題。

藉助 RDBMS
曲線救國。將多樣性資料來源的資料透過 ETL 灌到關係庫中,再基於關係庫出報表,這樣就可以避免多樣性資料來源的問題,轉而使用最熟悉的手段來解決。

不過,這種方式的侷限性很大。因為之所以出現多樣性資料來源,是因為各種資料來源有各自適用的場景,換句話說很多是關係庫搞不定的,所以才會用這些資料來源,比如 NoSQL 的 IO 吞吐能力很強,但計算能力較弱;文字 /Excel 檔案適合做臨時儲存且不需要持久化到 DB;Webservice 則非常靈活,入庫的動作就顯得過於笨重,…

且不說多樣性資料來源的資料是否能轉換到關係庫中,由於要經過 ETL 的過程,資料的實時性如何保證?資料量較大時除了 ETL 慢,RDBMS 的容量是否夠用?查詢效能是否滿足報表查詢要求?等等這些問題都是這種方式要面對的。

採用這種方式經常是“不得已”,因為解決某類問題上了其他資料來源,結果因為出報表又要用回關係庫,也不知道隱含了多少辛酸。

JAVA 硬編碼
透過 RDBMS 來解決報表多樣性資料來源的問題有這樣那樣的問題,那直接硬編碼怎麼樣?透過 JAVA 硬編碼對接多樣性資料來源為報表準備資料,畢竟硬編碼想幹啥就幹啥。

這種方式我們之前有分析過,除了編碼難、維護難的問題(報表開發人員基本搞不定),還存在無法熱切換(JAVA 是編譯型語言)和與業務應用緊耦合(程式碼要跟業務應用主程式一起打包部署)這些問題。這是我們之前聊過的:

硬編碼似乎也不理想。

事實上,我們只需要增強報表工具的計算能力就能解決這個問題。

1. 首先,提供多樣性資料來源的支援,透過報表工具可以連線這些資料來源,要實現這一步相對簡單;

2. 其次,提供複雜計算支援,讓所有的複雜計算都能在報表中完成。實現手段可以是強化呈現端的計算能力,透過報表格子表示式就能完成這些複雜計算。不過,對於繫結格子的計算(狀態式計算)想要支援複雜計算並不容易,在呈現端要兼顧資料處理和資料呈現很多計算就做不了了,而且呈現格會帶有很多呈現屬性(字型、顏色、邊框等等),帶著這些屬性計算會佔用過多記憶體,嚴重影響計算效能。

資料準備 ——報表開發中的深層次問題
很難在報表呈現格表示式中完成複雜計算(功能和效能都不滿足)

可以想到的另外一種方式是在報表中增加計算模組用來專門做多樣性資料來源混合計算,其位置與原來為報表準備資料的 SQL 和 JAVA 相當,只不過是內嵌在報表中,屬於報表自身的能力,結構大概是這樣

資料準備 ——報表開發中的深層次問題

在原有的基礎上增加了計算模組,計算模組可以透過可程式設計計算指令碼實現,但對這個指令碼能力有要求:

1. 提供多樣性資料來源訪問介面
能直接對接多樣性資料來源是基礎,種類越豐富對多樣性資料來源問題解決得越充分;

資料準備 ——報表開發中的深層次問題

2. 支援複雜計算
當資料來源自身不具備強計算能力時,透過指令碼可以完成報表資料準備階段的複雜計算邏輯,指令碼提供豐富的計算類庫,可以很方便地實現這類計算,最好比 SQL 和 JAVA 都簡單;

3. 支援多源關聯
可以跨異構資料來源關聯計算,這是也解決報表多樣性資料來源問題需要具備的重要能力;

4. 支援熱切換
指令碼修改後可以實時生效,而不會像 JAVA 一樣需要重啟應用。

當我們遇到報表多樣性資料來源問題需要選擇報表開發技術時不妨沿著這個方向考量一下。

擴充套件閱讀:

5. 報表的效能問題是怎樣產生的?

報表效能是總也避不開的話題,報表作為 OLAP(線上聯機分析)中的主要應用場景,無論從涉及資料的寬度(表數量),還是資料的廣度(查詢範圍)都可能非常巨大;而且在報表中還經常伴隨非常複雜的資料處理邏輯,這些都會影響報表的執行速度。而伺服器環境、資料庫環境、JDBC 效率、網路環境、客戶端環境這些也都都跟報表效能密切相關。

報表效能可能跟很多因素有關,非常複雜。這裡我們試著從報表執行的各個階段來分析報表效能問題產生的主要原因及其應對方法。未盡之處,歡迎討論。

我們知道報表執行主要分報表解析、資料準備、資料傳輸、報表計算和報表生成 5 個階段。除了報表解析是引擎載入解析模板,還未開始運算外,其他 4 個階段(示意圖中黃色的部分)均可能引起效能問題。

資料準備 ——報表開發中的深層次問題

我們在分析報表效能問題時一定要先定位是哪個階段引起的,抓主要矛盾。定位的方法也很簡單,就是分析報表執行日誌,很多報表工具都會輸出各個階段的運算時間,看看哪個階段耗時最長,就是問題發生的主要階段了。

1. 資料準備
報表資料準備是指從資料來源中讀取資料並將資料組織成報表可用的結果集的過程。在報表中往往是以資料集的形式存在,可以透過 SQL、儲存過程或 JAVA 實現。

資料準備並不是簡單地將資料來源的原始資料取出就結束了,而是會伴隨一些計算過程,有些還很複雜,可以想想一下平時我們開發報表時編寫的 SQL 絕大多數情況下都不是簡單的 select * from tbl。如果這個 SQL 比較複雜(由於大多數情況都是使用 SQL 準備資料,所以這裡我們僅以 SQL 為例,其他資料來源可以參考 SQL 資料集的解決辦法)執行較慢,就會導致報表變慢。

這個階段在資料庫中執行,本質上跑的快慢都跟報表無關,但好的報表工具是可以干預最佳化這個過程的(後面再說)。

資料準備階段慢,可以先試著最佳化 SQL,但 SQL 最佳化往往復雜度較高,所以也經常採用預計算的方式進行效能最佳化(這裡不討論硬體升級、資料庫擴容等物理最佳化手段)。

(1) 最佳化 SQL
我們知道複雜 SQL(關聯多、巢狀多)是比較難最佳化的。資料庫的透明化機制讓寫 SQL 時不用關心底層的執行順序,由資料庫最佳化器自動執行,這樣可以簡化編寫 SQL 的難度,但過於透明的機制讓我們很難干預 SQL 的執行路徑,也就很難最佳化 SQL 了。

(2) 預計算
SQL 無法最佳化或最佳化效果不理想時,透過預計算可以提升報表資料準備效率。將報表需要的結果集事先加工出來儲存到中間表中,報表查詢時直接讀取加工好的結果集,這樣就可以節省大量計算時間,從而提升報表效能。預計算本質是用空間換時間的手段。

不過,預計算的缺點也非常明顯,你不妨先思考一下有哪些問題?

主要的問題有兩個:時間問題和空間問題。

時間問題
預計算需要“事先”加工,其本質是一個 ETL 過程,這樣就會引起兩個時間問題,資料的實時性和預計算的時間成本。

報表基於預計算的結果查詢只能查詢預計算時點以前的資料,無法查詢預計算到當前時間的資料,這樣就導致了資料時效性差,不適合資料實時性要求高的業務場景(比如交易系統)。

預計算往往會放到業務空閒的階段進行,比如前一天夜裡到第二天上班前,通常還要預留一些時間容錯(跑失敗了要重新跑),這樣可能留給預計算的時間也就 5、6 個小時,這個時長基本是固定不變的,而資料規模、業務複雜度、報表數量都會不斷增長,未來極有可能會引發預計算跑不完而影響業務使用的問題。

空間問題
預計算的結果是要落地的,往往會儲存在資料庫物理表中,這樣的表多了會佔用大量資料庫空間,引起資料庫容量問題;另外這樣的表多了還會帶來管理上的問題。

預計算的應用範圍很窄,而 SQL 又比較難最佳化,還有什麼其他最佳化手段嗎?

(3) 藉助其他高效能運算引擎
在資料庫內搞不定報表資料準備階段最佳化時可以引入其他高效能運算引擎,這在業內並不少見,但幾乎所有技術都是採用獨立儲存 + 分散式架構來輸出高效能的,這對報表應用架構(主要是資料庫)的改變就有些大了,難度很大。

比較簡單直接的方式是在報表內部就能提供改變 SQL 執行路徑的手段,並且可以改善那些顯著低效的 SQL 演算法(比如 topN),這樣就可以在不改變應用架構的情況下實現資料準備階段的最佳化。

這就要求報表工具提供資料準備階段的計算能力,既可以分步執行 SQL(指定執行順序),還可以改善演算法效率。其表現形式可以是一種內建在報表工具中的計算指令碼,指令碼具備分步計算和強計算能力。

資料準備 ——報表開發中的深層次問題
報表工具計算模組提供可干預 SQL 執行路徑能力和高效的強計算能力


2. 資料傳輸
報表透過 JDBC 介面訪問資料庫讀取所需資料時,如果資料量比較大或者資料庫 JDBC 效能較差(要知道各種資料庫的 JDBC 效率是不同的)會導致資料傳輸時間過長,導致報表變慢。

由於我們沒法改變資料庫的驅動,我們只能在報表層面想辦法。一個可行的辦法是透過並行取數來提速。

(1) 並行取數
透過建立多個資料庫連線(這時要求資料庫相對空閒),採用多執行緒的方式同時讀取報表所需資料,可能是同一個表,也可能是多個表關聯計算後的結果,這樣資料傳輸的時間理論上就會縮短到原來的 1/n(n 是執行緒數),從而提升報表效能。

那麼這種並行取數實現起來難度如何呢?

因為目前大部分報表工具不支援並行取數,要想透過並行來加速資料傳輸只能自己使用 JAVA 硬編碼來做。我們曾經討論過在報表中使用 JAVA 硬編碼準備資料的弊端,而編寫並行程式難度又提升了一級,要知道,並行以後還要歸併(merge)各個執行緒的計算結果,merge 不是簡單地縱向拼接就完了,有時還涉及分組和順序。

使用支援並行取數的報表工具
比較簡單有效的方式是使用支援並行取數的報表工具,報表開發人員不需要考慮資料資源衝突、結果歸併等複雜問題就可以簡單實現。

(2) 非同步傳輸
當資料量較大時,可以透過非同步機制將資料分批返回給報表,報表接收部分資料後就立刻呈現,後臺同時進行不間斷的資料傳輸,這樣就可以提升報表的呈現速度。

非同步傳輸需要考慮很多方面,不建議自己硬編碼實現,最好使用支援非同步傳輸功能的報表工具,簡單快捷。

3. 報表計算
資料傳輸完成後,報表引擎會根據已準備資料和報表表示式運算報表,這個階段也是非常容易出現效能問題的。

效能問題常見於多資料集報表。

現在很多報表工具都提供了多資料集能力,允許開發者在一個報表中建立多個資料集,這樣可以分別組織資料,尤其當資料來自不同資料庫時,多資料集尤其方便。但這種方式為報表開發帶來便利的同時卻會帶來很嚴重的效能問題。

我們知道,多資料集的關聯是在報表單元格的表示式中完成的,類似這樣 ds2.select(ID==ds1.ID),報表引擎在解析這個表示式時會按照順序遍歷的方式完成關聯,即從 ds2 中拿出一條記錄,到 ds1 中遍歷,查詢 ID 相同的記錄;然後再拿第二條再去遍歷查詢;…
這個運算複雜度是平方級的,資料量小的時候沒什麼影響,資料量稍大時效能就會急劇下降。
資料準備 ——報表開發中的深層次問題

另外,報表單元格還帶有大量呈現屬性(顏色、字型、邊框等),帶著這些屬性運算也會拖慢報表的執行速度。所以,對於資料量較大的多個資料集,最好在資料準備階段使用更高效的關聯演算法完成關聯。

在資料準備階段完成關聯

將多資料集關聯轉移到資料準備階段完成,透過 SQL 就可以實施更加高效的關聯,只是 SQL 只能基於單一資料庫操作,如果資料來自多個資料來源時就不靈了。這時,最好報表工具在資料準備階段還提供諸如 HASH JOIN 等高效能關聯演算法,以便滿足異構資料來源時的關聯運算。HASH JOIN 演算法可以整體地看待幾個資料集,效率比報表工具採用的過濾式關聯要高得多,幾千行規模時幾乎是零等待。

4. 報表生成
報表計算完成後會生成引擎會將計算結果以 HTML 的形式輸出,生成最終要呈現報表。這個階段的效能問題主要有兩方面。

(1) 頁面渲染慢
當報表中新增了大量的呈現效果(隔行異色、背景圖、警戒色等)時,頁面渲染的速度就會變慢。減少過多的報表效果使用可以提升渲染速度;如果這些效果是必須的,那就要比拼使用的報表工具的能力了。

另外,如果報表單頁的內容過大也會影響頁面呈現的速度。對於比較高或者比較寬的報表呈現時建議採用分頁方式輸出,從而提升頁面呈現效率。

(2)客戶端環境差
總體上是跟使用者端環境有關係,比如網路問題、裝置問題等,遇到時需要具體分析。

透過了解報表執行各階段可能出現的效能問題,以及對應解決辦法,有些我們可以硬編碼或藉助其他技術來解決,有些還需要報表自身來提升。最直接的方式是使用能夠提供這些能力的報表工具,這個工具大概要具備這些特性才能幫助我們有效解決報表效能問題。

1. 支援分步
這樣可以有效最佳化 SQL 執行路徑,提升資料準備效率;

2. 內建強計算能力和高效演算法
能夠改善原有低效的演算法,提高資料計算效率;
支援 HASH JOIN 等高效能關聯演算法,以減少在呈現模板中進行多資料集關聯;

3. 支援並行取數
能夠透過多執行緒並行方式提升資料傳輸速度效率;

4. 支援非同步讀取
提供非同步取數非同步呈現機制,加速大資料量報表的呈現效率;

5. 支援多資料來源
提供多樣性資料來源介面,並能夠進行多資料來源關聯運算(同 2)。

擴充套件閱讀:


6. 什麼是大報表?

實際業務中有些報表比較“大”,查詢出的報表資料行數可以達到幾千萬甚至上億,這類行數很多的報表通常被成為“大報表”。大報表大部分情況下是清單明細報表,少量是分組報表。

大報表查詢通常不會採用一次性取出所有記錄再交給前端呈現的方式,因為這樣要等很久,使用者體驗極差;而且報表伺服器記憶體也吃不消。

常見的方式是透過分頁來呈現大報表,一次只取一小部分資料,取數結束後立刻交給前端呈現,當頁碼變化時再取出相應頁數的資料,這樣可以加快報表呈現速度,使用者幾乎沒有等待感。

具體如何實現呢?有幾種方式。

1. 資料庫分頁
業界最常用的做法是使用資料庫分頁來實現,具體來講,就是利用資料庫提供的返回指定行號範圍內記錄的語法。介面端根據當前頁號計算出行號範圍(每頁顯示固定行數)作為引數拼入 SQL 中,資料庫就會只返回當前頁的記錄,從而實現分頁呈現的效果。

主要藉助關聯式資料庫自身的能力,每種資料庫實現上會有所差異,Oracle 可以使用 rownum,mysql 則可以 limit,具體實現網上有很多資料這裡不再贅述。

資料庫分頁有沒有什麼不足?任何技術都有其應用範圍,資料分頁的問題主要集中在以下 4 點。

(1)翻頁時效率較差
用這種辦法呈現第一頁一般都會比較快,但向後翻頁時,所使用的取數 SQL 會被再次執行,並且將前面頁涉及的記錄跳過。對於有些沒有 OFFSET 關鍵字的資料庫,就只能由介面端自行跳過這些資料(取出後丟棄),而像 ORACLE 還需要用子查詢產生一個序號才能再用序號做過濾。這些動作都會降低效率,浪費時間,前幾頁還感覺不明顯,但如果頁號比較大時,翻頁就會有等待感了。

(2) 可能出現資料不一致
用這種辦法翻頁,每次按頁取數時都需要獨立地發出 SQL。這樣,如果在兩頁取數之間又有了插入、刪除動作,那麼取的數反映的是最新的資料情況,很可能和原來的頁號匹配不上。例如,每頁 20 行,在第 1 頁取出後,使用者還沒有翻第 2 頁前,第 1 頁包含的 20 行記錄中被刪除了 1 行,那麼使用者翻頁時取出的第 2 頁的第 1 行實際上是刪除操作前的第 22 行記錄,而原來的第 21 行實際上落到第 1 頁去了,如果要看,還要翻回第 1 頁才能看到。如果還要基於取出的資料做彙總統計,那就會出現錯誤、不一致的結果。

為了克服這兩個問題,有時候我們還會用另一種方法,用 SQL 遊標從資料庫中取數,在取出一頁呈現後,但並不終止這個遊標,在翻下一頁的時候再繼續取數。這種方法能有效地克服上述兩個問題,翻頁效率較高,而且不會發生不一致的情況。不過,絕大多數的資料庫遊標只能單向從前往後取數,表現在介面上就只能向後翻頁了,這一點很難向業務使用者交代,所以很少用這種辦法。

當然,我們也可以結合這兩種辦法,向後翻頁時用遊標,一旦需要向前翻頁,就重新執行取數 SQL。這樣會比每次分頁都重新取數的體驗好一些,但並沒有在根本上解決問題。

(3) 無法實現分組報表
除了清單報表,有時我們還要呈現大資料量的分組報表,報表包含分組、分組彙總及分組明細資料。我們知道,按頁取數按照翻頁每次讀取固定條數(一頁或幾頁)記錄,這樣根本無法保證一次性讀取一個完整分組,而分組呈現、分組彙總都要求基於整組資料來操作,否則就會出錯。

(4) 無法使用其他資料來源
資料庫分頁是藉助關聯式資料庫自身的能力,而對於非關聯式資料庫就不靈了。試想一下,NoSQL 怎麼用 SQL 分頁,文字怎麼做分頁?

報表的多樣性資料來源話題我們曾經討論過,在資料規模迅速膨脹的今天,基於非關聯式資料庫出報表已經非常普遍。


除了資料庫分頁,還有其他更好的方式嗎?

2. 硬編碼實現
我們發現基於資料庫的分頁方式強依賴資料來源,無法滿足其他資料來源型別的需要,也就是與資料庫緊耦合的。我們需要一個低耦合資料來源的實現方式以應對多樣性資料來源場景,還能同時解決效率、準確性和分組呈現問題。

按照主流的解題思路,可以透過編碼方式實現這個目標,實現思路大概是這樣:

基於資料庫時,
把取數和呈現做現兩個非同步執行緒,取數執行緒發出 SQL 後就不斷取出資料後快取到本地儲存中,呈現執行緒根據頁數計算出行數到本地快取中去獲取資料顯示。這樣,只要已經取過的資料就能快速呈現,不會有等待感,還沒取到的資料需要等待一下也是正常可理解的;而取數執行緒只涉及一句 SQL,在資料庫中是同一個事務,也不會有不一致的問題。這樣,兩個問題都能得到解決。不過這需要設計一種可以按行號隨機訪問記錄的儲存格式,不然要靠遍歷把記錄數出來,那反應仍然會很遲鈍。

基於非資料庫時,
同樣設定取數和呈現兩個非同步執行緒,取數時透過檔案遊標(或其他資料來源提供的分批取數介面)分批讀取資料並快取到本地,呈現階段則與上述方式完全一致。

然後再利用報表工具開放的介面和前端報表進行互動,完成報表的分頁呈現。

做分組報表時,
就需要一次性取出完整分組,在程式碼裡進行分組彙總,並將彙總結果插入結果集一併返回給前端報表進行呈現,同時還要設定分組記錄標誌位,以便前端報表在呈現時能夠為分組行設定不同的顯示效果(如加粗、標紅)。

實現後的效果類似下面這樣:
gif

取數執行緒不停地取數快取,呈現執行緒從快取中讀取資料呈現,總頁數不斷變化

透過上面的描述,可以看到自己硬編碼雖然可以實現,但複雜度很高。除了多執行緒程式設計,還要考慮快取資料儲存形式、檔案遊標、分組讀取與彙總,此外借助其他報表工具進行呈現時還要對方開放足夠靈活的介面,…,這些都是挑戰。

而且我們只考慮了呈現,如果還要匯出 Excel 怎麼辦?如果還要列印怎麼辦?畢竟報表既然能查就應該能匯出,能列印。這些需求在金融、製造行業都是真實存在的。


3 使用支援大報表的報表工具
如果前端使用報表工具開發報表,選用一個直接支援大報表呈現、匯出、列印的報表工具則更為直接。工具實現了兩個非同步執行緒的大報表機制,同時解決上面我們提到的問題,這些方面都封裝好直接使用。

大資料時代要支援大報表,這應該是報表工具必備能力。

擴充套件閱讀:



7. 中間表是什麼?和報表有什麼關係?會帶來怎樣的問題?

在資料庫中有一類用於儲存中間計算結果的物理表,通常被稱為“中間表”。中間表主要跟 OLAP(線上聯機分析)業務有關,產生的原因主要有以下幾方面。

資料準備 ——報表開發中的深層次問題

中間表來源

1. 計算邏輯複雜
在 OLAP(報表或查詢)業務中,有些計算邏輯很複雜,每次都從頭寫會導致報表開發過於繁瑣,而且有的計算用 SQL 很難寫出來。這時會採用中間表事先計算好,再基於預計算的中間結果開發報表。

計算邏輯複雜常見於報表業務中,以固定報表最為常見;多維分析則比較少見。

2. 查詢效能差
當查詢涉及的資料量很大或者計算邏輯很複雜時查詢效能會很差。為了提升查詢效能,增強使用者體驗,通常會把彙總結果實現計算出來儲存在中間表中。基於預彙總的中間表查詢速度會快很多。

在實際業務中,大部分提升查詢速度的中間表也都是為報表服務的。

3.ETL 過程轉存
ETL 過程也會產生中間表。ETL 過程中常常會涉及到資料庫的資料,正常的 ETL 過程應當是 E、T、L 這三個步驟逐步進行,也就是先清洗轉換之後再載入進資料庫,最後在資料庫中的只是合理的結果資料。但是,E(清洗)和 T(轉換)這兩個步驟中會涉及到大量資料計算,而在資料庫外實施這些計算很不方便,所以實際情況就會是把涉及到的所有資料都先載入進來然後再進行清洗和轉換,ETL 過程變成了 ELT 甚至 LET。事先要載入的這些資料在關聯式資料庫中也必須以表的形式儲存,這就使資料庫中增加了許多並非最終需要的中間表。

如果觀察一下這些跑批任務,你會發現 ETL 任務很多都是為報表業務服務的。

4. 多樣性資料來源混合計算
另一種情況是多樣性資料來源造成的,這也是為資料呈現(報表查詢)服務的。現代應用中的資料呈現經常會涉及資料庫外的資料,目前一般的做法是把庫外資料定時匯入到資料庫中,然後就能和資料庫內的資料一起運算產生報表,否則很難實現資料庫內外的資料的混合運算。這當然也會讓資料庫中多了一些表,而且,有些網際網路上取過來的資料常常是多層的 json 或 XML 格式,在關聯式資料庫中還要建立多個關聯的表來儲存,會進一步加劇中間表過多的問題。

透過列舉的 4 箇中間表產生的主要原因,我們發現一個共同點:中間表大部分情況都是為報表服務的。我們也知道,實際業務中的報表數量非常多,而且報表業務業務不穩定經常會新增修改報表,這會導致中間表數量不斷增多。

中間表會帶來哪些問題

中間表是一把雙刃劍,提供很多便利的同時也會帶來一些問題。

我們曾在一個運營商的報表系統中,發現了一個讓人吃驚的現象。在 DB2 資料倉儲中,有兩萬多個資料庫表!經過深入瞭解發現,真正的原始資料表只有幾百張,剩下的大量的資料庫表都是為查詢和報表服務的中間表。

像這種系統經過幾年乃至十幾年的執行,資料庫中的中間表越來越多,甚至出現這種上萬個的情況並不少見。大量中間錶帶來的直接困擾是資料庫儲存空間不夠用,面臨頻繁的擴容需求。中間表對應的儲存過程、觸發器等等需要佔用資料庫的計算資源,也會造成資料庫的擴容壓力。

中間表過多還會帶來管理方面的問題,對於成千上萬張中間表想要梳理清楚恐怕是一件非常頭疼的事情。

那麼,是不是可以清理掉一些不用的中間表?一般的結論都是:搞不動。資料庫中的中間表是不同程式設計師製作的,有的是綜合查詢系統使用,有的是報表系統使用。中間表之間還存在交叉引用,有些程式設計師看到有別人生成的中間表就直接使用了。有時候一些查詢報表已經廢棄不用了,但是對應的中間表沒人敢刪,因為不知道刪掉之後會影響其他什麼查詢或者報表。

很多情況下,專案組只好為了越來越多的中間表去擴容資料庫。但是資料庫的擴容成本太昂貴了:不管是換更強的伺服器(縱向擴容),還是增加資料庫伺服器的節點(橫向擴容),都不便宜。

總結來說,中間表會帶來管理、容量和效能三方面的問題。

如何解決中間表的問題?

可以很容易想到的方式是使用庫外檔案儲存中間表資料,這樣中間表脫離了資料庫就不會對資料庫再產生影響。但是,在實際應用中這種辦法卻很少使用。為什麼呢?

我們知道,中間表是要再計算的,基於中間表查詢的報表還要進行資料過濾,有的還要再次彙總,還可能涉及關聯計算,這些操作在資料庫裡透過 SQL 完成很簡單。但是檔案沒有計算能力,要實施這些計算只能硬編碼,用 JAVA 來做,使用 JAVA 來做集合運算又非常麻煩,遠沒有資料庫(SQL)方便。所以採用檔案儲存中間表的方式使用並不廣泛,主要是由實現複雜度過高導致的。

那還有什麼好的方式呢?

使用支援檔案源的報表工具
既然中間表大部分是為報表服務的,而透過將中間表外接到檔案中可以解決中間錶帶來的這些問題,那麼直接使用支援檔案源的報表工具是否就可以了呢?

答案是肯定的。

我們來看一下要實現這個目標,報表工具要具備哪些能力?

(1) 豐富的計算類庫
要解決文字計算難的問題,報表工具要提供豐富的計算類庫,除了能完成所有資料處理任務(都能算)以外,還要實現簡單,這是基礎,太複雜了沒法用;

(2) 多樣性資料來源介面
支援多樣性資料來源以後,就可以不用透過資料庫中轉直接讀取多樣性資料來源資料出報表;

(3) 異構資料來源混合計算能力
提供多樣性資料來源介面後,還要能夠進行異構源間的混合計算,這樣就可以徹底解決掉多樣性資料來源帶來的中間表問題;

(4) 高效能
除了實現簡單以外,計算效能也要有保障,從而滿足前端報表查詢的效能需要。

具體實現上可以在報表工具中增加計算模組來對接“庫外中間表”,結構類似這樣

資料準備 ——報表開發中的深層次問題

其中庫外中間資料檔案可以採用本地檔案,也可以使用網路或分散式檔案系統,或其他資料來源。

要解決中間表問題,需要報表工具強化自身的計算能力才能實現!

擴充套件閱讀:



8. 報表熱切換是什麼意思?

熱切換(Hot Swap)是指在系統不停機的情況下更換系統部件,在報表業務中則是指在不重啟報表及相關應用的情況下完成對報表的維護(新增、修改、刪除),冷切換則恰好相反。

報表業務很不穩定,業務開展的過程中會刺激出更多查詢統計需求,如果每次需求實現後都要等系統空閒(往往是非工作時間)時重啟系統才能讓修改後的報表生效,那將會對業務使用造成非常大影響(延遲)。因此在需求經常會變化的報表業務中,熱切換顯得尤其重要。

事實上,在報表業務中要實現熱切換並不難,只要在開發報表時選擇合適的技術手段,避免使用諸如 JAVA 這樣的編譯型語言(雖然重寫類載入器可以變相實現熱載入,但過於繁瑣,也沒從根本上解決問題)即可。

但在實際應用中我們卻看到大量使用 JAVA 來開發報表,造成無法熱切換的情況。為什麼會這樣?

報表業務有兩個特點,一個是 報表業務很複雜。報表是一項負責綜合性統計的任務,將原始資料加工成業務需要的報表形式要走很長的路,不僅資料處理邏輯繁瑣,報表呈現樣式也千奇百怪,所謂中國式複雜報表。

另一個特點是 嵌入使用。報表經常會作為應用系統的一部分(模組)嵌入到系統中使用。

現在報表呈現格式方面的問題已經基本得到解決,以國內成熟報表工具為主導的一批國產軟體可以很好地解決中國式複雜報表呈現的問題,而且這些工具大多數採用解釋執行機制,報表模板修改後可以實時生效。

但資料準備階段的問題卻一直沒有解決,複雜的資料處理和業務邏輯控制讓開發人員不得采用硬編碼手段來實現。由於大部分應用系統都採用 JAVA 開發,既然報表是系統的一部分,業務邏輯又這麼複雜,硬編碼的首選自然是 JAVA 了。這是導致在報表中大量使用 JAVA 導致無法熱切換的原因。

那麼如何解決這個問題?

將報表的資料準備也工具化!

早期,報表開發完全靠硬編碼的時代,大家也普遍採用 JAVA 來“畫”報表,這樣勢必存在無法熱切換的問題,後來報表工具出現解決了呈現模板的熱切換問題。所以,要徹底實現報表熱切換,將資料準備也工具化是一個可行的方向。

然而,報表的資料準備和報表呈現兩個階段分別使用不同工具會造成報表開發和維護上的困擾,因此,最好的方式是增強報表工具自身的計算能力,將兩個階段都融入可以解釋執行的報表模板中,從而徹底實現報表熱切換。

我們知道,報表工具本身具備一定的計算能力,在呈現模板的單元格中可以編寫分組、求和、比值等表示式,但由於格子的限制很難處理複雜的資料邏輯,這也是為什麼在報表中需要資料集(JAVA/SQL)來準備資料的原因。

一個可行的辦法是在報表工具中增加可解釋執行的計算指令碼(模組)用於資料準備,這樣在計算模組中可以實現任意複雜的資料處理邏輯,同時解釋執行的指令碼內建在報表模板中實現熱切換。

資料準備 ——報表開發中的深層次問題

報表計算模組(指令碼)要具備這樣一些能力: 1. 解釋執行
這是實現熱切換的基本能力,資料準備和報表呈現內建在一個報表模板中,採用解釋執行機制執行;

2. 計算體系完善
能實現所有的資料處理任務,原來在 JAVA 中的報表資料準備計算在指令碼中都應該能完成,具備豐富的集合運算類庫;

3. 易開發維護
實現上要足夠簡單,這樣報表開發人員就能直接搞定資料準備和報表呈現,而不再依賴其他專業程式設計師;同時在一個報表模板裡更易於維護。

參考資料:

9. 報表沒完沒了是個什麼狀況?

可以先想一下自己的部門或專案組是否面臨這些問題:
1. 投入很多技術力量做報表,卻還是疲於應付
2. 用了高階報表工具和敏捷 BI,卻還是不夠用
3. 技術高手用來做報表,感覺很浪費 4. 對於頻繁多變的報表需求,需要低成本應對方案

專門用於統計分析的報表業務有一個特點,就是業務穩定性非常差。在業務開展過程中會催生很多新的查詢需求,而且已實現的查詢需求還會經常變化,這就造成了沒完沒了的報表。所以經常會有這麼一段對話

資料準備 ——報表開發中的深層次問題

報表沒完沒了是需求使然,無法規避,只能適應,而目前主要的是問題是普遍缺少一種低成本的方案來適應沒完沒了的報表。

為什麼報表開發成本一直居高不下?

我們知道,報表工具的主要作用是將報表呈現階段的開發工具化,使用報表工具可以將原本需要硬編碼的工作透過工具來提高生產效率;但報表開發的另一個階段:資料準備,卻仍然在使用原始的硬編碼方式處理,有時我們要編寫非常複雜的 SQL、儲存過程和 JAVA 程式,這樣的工作通常要依賴高水平的技術人員才能完成。

另外,採用過於原始手段會帶來報表維護困難,複雜的程式碼無論從編寫還是修改都比較困難,這樣又會加劇報表開發成本居高不下!

除了技術原因外,還有應用結構和團隊管理方面的因素也會造成報表開發的成本居高不下。在許多應用系統中,報表是耦合在其中的一些功能,而業務系統的技術環境很複雜,這就迫使報表開發人員也要熟悉這些東西,也就很難把報表開發人員和業務系統的開發人員分開,業務系統上線之後,開發人員仍然要繼續堅守開發報表,很難把這項工作轉交給客戶方的運維人員。

開發過程中的有效溝通也會影響工作量。我們經常會發現這樣的現象:業務人員提出報表需求,等技術人員做好後才發現某些概念術語的理解有誤,統計口徑不一致,結果並不是業務人員想要的,然後也只能重做,甚至反覆多次才能正確實現,嚴重浪費開發資源。


如何解決報表開發成本過高?如何低成本地應對沒完沒了的報表?

可以嘗試透過如下五個步驟來解決這些問題。

資料準備 ——報表開發中的深層次問題

1. 引入報表工具

先把最容易解決的問題解決掉,透過引入專業的報表工具解放報表資料呈現階段的人力,報表工具可以完成包括中國式複雜報表在內的各種圖表呈現。選擇成熟且價效比高的工具是這個階段的主要目標。

資料準備 ——報表開發中的深層次問題

2. 增加計算模組

引入報表工具後,解放了資料呈現階段的人力,降低了一定的成本,但佔主要部分的報表資料準備階段仍未解決。

資料準備階段的特點是:1. 編碼困難,沒有普適的工具 2. 對人員要求高,需要高水平技術人員完成 3. 實現週期過長,難以適應多變的報表需求 4. 硬編碼耦合性高,依賴資料庫和 JAVA 都都會造成緊耦合 5. 運維過於複雜,修改維護成本提高

這時,我們需要沿著第一步的方向繼續前進,將資料準備階段也工具化。比較好的方式是
在報表工具中增加用於資料準備的計算模組,將原來使用 SQL/ 儲存過程 /JAVA 實現的資料準備演算法,全部透過計算模組完成,使得報表開發徹底工具化,簡化開發,降低成本。

資料準備 ——報表開發中的深層次問題

計算模組的能力可以透過指令碼來實現,在指令碼中內建各種豐富的計算類庫,讓報表開發人員獨立就能完成資料準備階段的工作,從而全面接管報表的開發,而不再依賴其他專業程式設計師。

這裡尤其要注意,報表計算模組需要具備這樣一些能力。

1. 易於編碼
包含豐富的計算類庫,可以很方便地完成各類資料計算任務;必要時還能提供視覺化的編輯除錯環境進一步簡化這個階段的開發;

2. 支援熱切換
計算模組需採用解釋執行機制,這樣可以很好地和前端報表呈現模板結合在一起,報表修改後可以實時生效,無需重啟整個應用;

3. 支援多樣性資料來源
提供 RDB、NoSQL、文字、Excel、hadoop 等多樣性資料來源介面,報表直接基於多言行資料來源開發,也可以進行混合計算(如 Excel 和 RDB 的表 join);

4. 高效能
計算模組的計算效能不能低於原來 SQL/JAVA 的計算效能,最好高於原來的實現方式。

報表開發全面工具化以後,就可以獲得更高的報表開發效率,進一步降低報表開發成本。

3. 獨立報表模組

報表開發全面工具化以後,就可以著手梳理應用結構,獨立報表模組,從而將報表模組從業務系統中解耦出來。

1. 梳理資料來源
首先梳理資料來源,將報表業務相關的資料來源都整理出來,以後的報表開發只需要和這些資料來源打交道;同時為下一步剝離報表業務做準備。
資料準備 ——報表開發中的深層次問題

2. 剝離報表業務
將資料來源和業務應用中與報表相關的資料準備(複雜 SQL、儲存過程、中間彙總表、自定義 JAVA 類)全部轉移到報表工具中實現;同時將這些內容從資料庫和業務應用中清除,完成報表業務剝離。
資料準備 ——報表開發中的深層次問題

3. 獨立報表模組
報表業務完全剝離後,在報表工具中實現的報表在物理上就可以獨立於資料來源和業務模組儲存,不再與業務系統和資料來源緊密耦合,完全獨立報表模組

4. 調整應用結構
獨立報表模組後,報表模組與業務模組共享資料儲存;應用系統呼叫報表模組為使用者輸出報表結果;同時解釋執行報表模組支援熱切換,即改即用,無需重啟應用。
資料準備 ——報表開發中的深層次問題

獨立報表模組以後,報表就可以單獨修改和維護,清晰的應用結構會進一步降低報表開發成本。

4. 建設報表團隊

報表模組獨立後,建設專門的報表開發團隊,不再需要高成本應用程式設計師或 DBA 參與報表開發,進一步降低報表開發成本。
資料準備 ——報表開發中的深層次問題

報表開發人員就無需應對紛繁複雜的應用環境,更無需關係應用架構,只需根據已有架構開發報表就可以了。半年以上工作經驗的技術人員就能勝任(其實,理工科應屆畢業生就可以了,甚至高中學歷都行)。

簡化報表開發後,還可以嘗試將持續的報表開發工作移交給客戶方的本地運維人員,這樣不僅能降低開發商的成本,還能提高對客戶的響應速度。

5. 完善溝通機制

最後就是建立有效的溝通機制,減少交流中的誤解。

一個簡單可行的辦法就是建立企業內部的報表知識庫,技術形式上搞一個論壇即可。把以前做過的報表收集到論壇上加以評註,並提供搜尋功能。
資料準備 ——報表開發中的深層次問題

當有了新的報表需求時,可以搜尋歷史庫中是否曾經做過類似的報表(出現過相同的業務術語)。歷史報表中保留有相關程式碼或公式,而這些形式化的資訊不會有歧義,這就能幫助新的開發人員正確理解業務術語。
資料準備 ——報表開發中的深層次問題

甚至許多報表部分還可以被直接複用,在人員變動時也可以最大限度地保證業務知識的繼承。
資料準備 ——報表開發中的深層次問題


應對報表沒完沒了是一個長期的過程,是涉及技術、管理等諸多方面的綜合性事務。當這些步驟完成以後就可以全方位應對沒完沒了的報表了。

擴充套件閱讀:

一勞永逸地“解決”沒完沒了的報表開發

結語

報表做不完,都賴資料來源;報表開發快與慢,資料準備是關鍵。

透過提升報表工具的資料準備能力可以解決大部分報表開發過程中的深層問題, 從而透過改進生產工具來提升生產效率。這樣,在選擇報表工具時,除了能滿足呈現方面的需求外,也要關注工具本身的資料準備能力,自然是越強越好。

關於當前主流報表工具在這方面的能力,可以搜尋“十大活躍報表深度點評”,其中有深入的評論。

我們還將持續關注報表開發中遇到的各類難題,對這方面感興趣的同學可以再搜尋“乾學院”上的免費商業智慧課程,進一步瞭解和學習。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69900830/viewspace-2702546/,如需轉載,請註明出處,否則將追究法律責任。

相關文章