報(bào)表工具的二次革命
【數(shù)據(jù)猿導(dǎo)讀】 報(bào)表工具是一個(gè)歷史比較悠久的軟件類產(chǎn)品了,已經(jīng)有 20 年以上的發(fā)展歷史了,在這 20 多年中,產(chǎn)品在不斷的更新迭代,不斷的隨著需求的改變而進(jìn)步完善,持續(xù)發(fā)揮著自己的價(jià)值

在這無數(shù)次的更新迭代中,又有兩次比較大的變革,極具重要意義,可以算作是工具發(fā)展史上的兩大里程碑式的革命,對軟件的發(fā)展走向起到了決定性的作用。
先回顧第一次革命
第一次革命發(fā)生在報(bào)表工具誕生的初期,當(dāng)時(shí)基礎(chǔ)類,工具類軟件,基本都是國外軟件的天下,報(bào)表工具似乎也不例外,外國人帶著他們的報(bào)表工具進(jìn)入中國,也想像數(shù)據(jù)庫一樣,占領(lǐng)和收割國內(nèi)的龐大軟件市場,但是這一次他們折戟了,國外的報(bào)表工具不僅沒有成功,反而是被國產(chǎn)的工具打的落花流水,甚至連開源免費(fèi)的也被打趴下了。
為什么一向厲害的國外軟件在報(bào)表領(lǐng)域卻沒有打敗國產(chǎn)的呢?
剛進(jìn)入國內(nèi)的國外報(bào)表軟件,其實(shí)在前期也打開了一定的市場,形成了一定的規(guī)模,知名度也挺高,比如水晶報(bào)表,但是很快就漏出疲態(tài),由于產(chǎn)品處于初期階段,而且歐美人的表格可能也比較簡單,這些國外報(bào)表工具,使用上很不方便,只能做簡單的表格。
可以看看下面這倆,看著就有點(diǎn)蒙圈,不知道該怎么弄了,完全和我們平時(shí)看到的表格不一樣,增加學(xué)習(xí)成本不說,即使學(xué)會了也不用,做不了復(fù)雜的表格。
這時(shí)候,報(bào)表工具的第一次革命就來了。
面對這些國外工具解決不了的難題,國內(nèi)報(bào)表工具的代表廠商,潤乾報(bào)表,在研究了無數(shù)復(fù)雜表樣后,開發(fā)出了全新一代的類 EXCEL 的工具,創(chuàng)造出了獨(dú)一無二的非線性報(bào)表模型,不僅學(xué)習(xí)簡單,操作方便,而且可以輕松做出各類中國式復(fù)雜報(bào)表。
這次革新,不僅讓國產(chǎn)軟件打敗了國外軟件,而且國產(chǎn)廠商也重新定義了報(bào)表軟件的標(biāo)準(zhǔn),此后的工具,就全都是好用的 EXCEL 方式的操作,和模仿非線性報(bào)表的復(fù)雜報(bào)表模型了。
再來說第二次革命
一次革命后,復(fù)雜報(bào)表的制表方面的難題就基本都解決了。
但隨著行業(yè)的發(fā)展,我們又慢慢發(fā)現(xiàn),雖然報(bào)表工具已經(jīng)很牛,什么復(fù)雜表格都能做,但有些時(shí)候,報(bào)表開發(fā)還是很讓人頭疼,因?yàn)榻o報(bào)表準(zhǔn)備數(shù)據(jù)有時(shí)候是一件更困難的事情。
做過實(shí)際項(xiàng)目開發(fā)的工程師都知道,應(yīng)用中的報(bào)表,有 80% 的數(shù)據(jù)來源和計(jì)算都比較簡單,很多一個(gè)簡單的 SQL 語句就搞定了,但還有 20% 的情況中,數(shù)據(jù)準(zhǔn)備工作就沒有那么好做了,一些過程式的多步驟復(fù)雜計(jì)算,常常要寫很長的多層嵌套的 SQL 或者存儲過程才能搞定,如果數(shù)據(jù)來源再復(fù)雜一些,要對各類數(shù)據(jù)源混算,一些非關(guān)系數(shù)據(jù)庫或者文本數(shù)據(jù)源都不支持 SQL 了,那還得用 JAVA 等語言來寫,SQL 10 幾行能寫完的,JAVA 恨不得寫出幾百行來,編碼難度和效率就更糟糕了。
然而恰恰是這僅占 20% 的需要硬編碼來做復(fù)雜數(shù)據(jù)準(zhǔn)備的工作,卻占了我們 80% 的工作量。
而且,隨著系統(tǒng)不斷的開發(fā)使用,這些存儲過程,中間表,JAVA 程序,也都會慢慢的累積起來,越來越多,導(dǎo)致應(yīng)用高度耦合,維護(hù)困難。
另外,隨著大數(shù)據(jù)時(shí)代的到來,報(bào)表的性能問題也變的格外突出,單純通過報(bào)表工具的運(yùn)算能力來解決性能問題已經(jīng)有點(diǎn)捉襟見肘。
怎么解決這些新的難題呢,這就喚起了報(bào)表工具的二次革命。
雖然數(shù)據(jù)準(zhǔn)備、優(yōu)化應(yīng)用這些事已經(jīng)不完全算是報(bào)表工具能力應(yīng)該覆蓋的范疇,工程師們也都非常理解,但只要是和報(bào)表相關(guān)的難題,作為一個(gè)報(bào)表廠商,急用戶之所急,我們就得想辦法去去克服這個(gè)難題。
第二次革命,是提升數(shù)據(jù)準(zhǔn)備能力,優(yōu)化應(yīng)用結(jié)構(gòu)和提升性能的革命。
集算器,SPL,就是潤乾發(fā)起二次革命,解決上面這些新問題的利器,而且是開源免費(fèi)的,不僅在國內(nèi)有很多開發(fā)商在用,國外也有龐大的用戶基礎(chǔ),不僅潤乾報(bào)表可以用,也可以配合其他報(bào)表工具來用。
集算器 SPL
SPL 是一個(gè)中間計(jì)算層,類似于數(shù)據(jù)中臺,它可以輕松解決項(xiàng)目中的數(shù)據(jù)準(zhǔn)備開發(fā)難題,可以優(yōu)化應(yīng)用結(jié)構(gòu),提升運(yùn)算性能。
下面我們就來具體看下 SPL 是怎么解決這三個(gè)方面的難題的。
降低報(bào)表數(shù)據(jù)準(zhǔn)備開發(fā)難度
·丨比 JAVA 和 SQL 更易寫
當(dāng)前復(fù)雜報(bào)表的數(shù)據(jù)準(zhǔn)備工作一般是采用 JAVA 或 SQL 完成的,存儲過程以及中間表也可以看作是 SQL。SPLSPL 的語法比 JAVA 和 SQL 更為簡單易懂,采用 SPL 能在很大程度上簡化這些開發(fā)量。
JAVA 等語言沒有提供批量數(shù)據(jù)計(jì)算的類庫,寫個(gè)簡單的 SUM 也要好幾行,更何況分組、連接等運(yùn)算,而對于過濾、匯總用到的通用表達(dá)式計(jì)算,基本上是大多數(shù)應(yīng)用程序員無法完成的任務(wù)了。
SPL 則提供了大量與結(jié)構(gòu)化計(jì)算相關(guān)的基礎(chǔ)對象和方法,分組匯總這些只要一句,而且是解析執(zhí)行的動態(tài)語言,可以進(jìn)行隨意的表達(dá)式計(jì)算。使用 SPL 完成報(bào)表數(shù)據(jù)準(zhǔn)備工作要比 JAVA 容易得多,代碼也要短小很多,這一點(diǎn)很好理解,就不具體舉例了。
代碼短小不僅是寫得更快,而且還能容易理解算法和排錯(cuò),絕大多數(shù)報(bào)表的數(shù)據(jù)準(zhǔn)備算法可以在一個(gè)屏幕內(nèi)顯示出來,可以更直觀地理解代碼的整體含義。而使用 JAVA 時(shí),一個(gè)完整的業(yè)務(wù)邏輯常常需要幾百行代碼,翻看到后面時(shí)已經(jīng)忘了前面的了。
有經(jīng)驗(yàn)的程序員都知道,SQL 用來實(shí)現(xiàn)很零碎的多步運(yùn)算很不方便,特別是與次序相關(guān)的運(yùn)算,程序員常常要把數(shù)據(jù)從數(shù)據(jù)庫中取出來用 JAVA 等完成。而 SPL 則正好在這方面做了強(qiáng)化,在分步計(jì)算、集合化、有序計(jì)算和對象引用等幾方面做了完善,對于常用的日期和字串等運(yùn)算,也比大部分 SQL 提供了更豐富的方法。
舉個(gè)例子,我們要算某支股票最長連續(xù)漲了多少交易日。
SQL 的寫法:
select max(continuousDays)-1
from (select count(*) continuousDays
from (select sum(changeSign) over(order by tradeDate) unRiseDays
from (select tradeDate,
case when closePrice>lag(closePrice) over(order by tradeDate)
then 0 else 1 end changeSign
from stock) )
group by unRiseDays)
SPL 的寫法:
1 =stock.sort(tradeDate)
2 =0
3 =A1.max(A2=if(closePrice>closePrice[-1],A2+1,0))
許多情況用 SQL 也不是寫不出來,但不能直接按自然思維實(shí)現(xiàn),很費(fèi)腦筋,這種代碼放時(shí)間長了程序員自己都會忘了是怎么寫出來的,給將來的維護(hù)也造成麻煩。SPL 代碼則符合自然思維習(xí)慣,即使是與 SQL 相同的思路也能更清晰地表達(dá),更容易理解和維護(hù)。
SPL 簡化 SQL 編碼的例子很多,有興趣可以去參考: 4 SPL 方案與案例
(http://c.raqsoft.com.cn/article/1647044867607)
不過,需要說明的是,SPL 雖然在大多數(shù)情況下的語法要比 SQL 更簡單易寫,但并不能完全取代 SQL。數(shù)據(jù)從數(shù)據(jù)庫讀出的 IO 成本相當(dāng)高,有些涉及數(shù)據(jù)量太大的簡單運(yùn)算,數(shù)據(jù)讀出的耗時(shí)遠(yuǎn)遠(yuǎn)超過運(yùn)算本身,這種情況還是放在數(shù)據(jù)庫中運(yùn)算更合適。
·丨比報(bào)表中計(jì)算更廣泛
報(bào)表工具都可以完成計(jì)算列、分組排序等運(yùn)算,潤乾報(bào)表還提供了跨行組運(yùn)算和相對格與集合的引用方案,可以完成更復(fù)雜一些的運(yùn)算。
報(bào)表工具中的運(yùn)算是一種狀態(tài)式的計(jì)算,也就是把所有計(jì)算表達(dá)式寫在報(bào)表布局上,由報(bào)表工具根據(jù)依賴關(guān)系決定計(jì)算次序。這種方法好處是很直觀,在依賴關(guān)系不太復(fù)雜時(shí)能一目了然地了解各單元格的運(yùn)算目標(biāo)。
但是,在依賴關(guān)系較為復(fù)雜,數(shù)據(jù)準(zhǔn)備計(jì)算需要分成多步時(shí),狀態(tài)式計(jì)算就困難了,要實(shí)施過程式計(jì)算,經(jīng)常需要借用隱藏格,隱藏格不僅將破壞狀態(tài)式運(yùn)算的直觀性,由于狀態(tài)式計(jì)算一般需要全內(nèi)存處理依賴關(guān)系,還會占用更多不必要的內(nèi)存。而且還有許多運(yùn)算即使用隱藏格也難以完成。
比如統(tǒng)計(jì)各地區(qū)前五的銷售業(yè)績,第六名以后全部歸并為其他。
如果不借助數(shù)據(jù)準(zhǔn)備環(huán)節(jié),就要在報(bào)表中使用隱藏行列手段將不該列出來的條目隱藏,而不能直接過濾掉。
單純報(bào)表工具實(shí)現(xiàn):
SPL 做好數(shù)據(jù)準(zhǔn)備后 + 報(bào)表工具實(shí)現(xiàn)。
再比如帶明細(xì)的分組報(bào)表要按匯總值排序,需要先分組后排序,許多報(bào)表工具無法控制這個(gè)次序,報(bào)表就無法完成了。
還有個(gè)典型例子是舍位平衡,明細(xì)值四舍五入后再合計(jì),可能會與合計(jì)值的四舍五入值不相等,會造成了報(bào)表上明細(xì)與合計(jì)數(shù)值不一致,這時(shí)需要根據(jù)合計(jì)的舍入值倒推明細(xì)的舍入值,這不是報(bào)表工具能搞定的事了。
這幾個(gè)運(yùn)算的邏輯都很簡單,但在報(bào)表工具中卻很難實(shí)現(xiàn),單句的 SQL 也很難寫,而為了這種簡單且無復(fù)用價(jià)值的運(yùn)算寫一段 JAVA 程序或存儲過程顯得很無聊,況且也不是很輕松。但是,如果采用 SPL 就會容易得多,在數(shù)據(jù)準(zhǔn)備階段完成計(jì)算,報(bào)表只負(fù)責(zé)呈現(xiàn)少量的直觀計(jì)算,能有效地保持狀態(tài)式計(jì)算的優(yōu)勢。過程多了一步,但結(jié)構(gòu)更為清晰。
SPL 還能輕松實(shí)現(xiàn)動態(tài)數(shù)據(jù)源和數(shù)據(jù)集。
報(bào)表工具使用的數(shù)據(jù)源一般事先配置好了,不能根據(jù)參數(shù)動態(tài)選擇,而使用 SPL 數(shù)據(jù)源時(shí)則可以用腳本控制連接不同的數(shù)據(jù)源。
另外 SPL 還能協(xié)助處理格式。
比如許多報(bào)表工具都支持縱向分欄,但很少有報(bào)表工具支持橫向分欄。而用 SPL 可以將原數(shù)據(jù)集變換成橫向拼接過的數(shù)據(jù)集,報(bào)表工作只要用普通的模板呈現(xiàn)列數(shù)更多的數(shù)據(jù)集即可。
·丨一致的多樣性數(shù)據(jù)源支持
現(xiàn)代報(bào)表的數(shù)據(jù)源并不只是數(shù)據(jù)庫,還可能是文本文件或 json、XML 等。這些非數(shù)據(jù)庫數(shù)據(jù)源沒有再計(jì)算能力,但出報(bào)表時(shí)總還是需要再進(jìn)行一些過濾分組甚至多表連接等運(yùn)算,報(bào)表工具本身的計(jì)算能力不足,一般都不能很好地處理 json 和 XML 數(shù)據(jù),即使針對能進(jìn)行簡單處理的結(jié)構(gòu)化文本,由報(bào)表工具運(yùn)算也也會造成容量負(fù)擔(dān)過重的問題。因此,我們經(jīng)常會有一個(gè)過程把這些非數(shù)據(jù)庫數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫再去生成報(bào)表,增加開發(fā)工作量。
如果采用 SPL 準(zhǔn)備數(shù)據(jù),則可以直接用這些非數(shù)據(jù)庫數(shù)據(jù)作為數(shù)據(jù)源去生成報(bào)表,不需要導(dǎo)入數(shù)據(jù)庫的過程,減少開發(fā)工作量。
比如:json 文件存儲了客戶名單及其銷售額,要找出銷售額累計(jì)占到一半的前 n 個(gè)大客戶,并按銷售額從大到小排序。
1=json(file("d:\\sales.json").read()).sort(amount:-1)取數(shù)并逆序排序
2=A1.cumulate(amount)計(jì)算累計(jì)序列
3=A2.m(-1)/2最后的累計(jì)值即是總和
4=A2.pselect(~>=A3)超過一半的位置
5=A1(to(A4))按位置取值
更多例子可以參考:報(bào)表工具怎樣使用 Json/XML 的數(shù)據(jù)(http://c.raqsoft.com.cn/article/1640858385206)
而且一般報(bào)表工具使用的數(shù)據(jù)集都是類似 SQL 返回的那種單層二維表,碰到象 json 或 XML 這類多層數(shù)據(jù)只能先轉(zhuǎn)換成多個(gè)單層數(shù)據(jù)集,再在報(bào)表模板中關(guān)聯(lián)運(yùn)算拼接成多層報(bào)表。而 SPL 可以直接支持多層數(shù)據(jù)集計(jì)算,不需要做這個(gè)轉(zhuǎn)換,減少工作量,潤乾報(bào)表也可以接受 SPL 返回的多層數(shù)據(jù)集直接按層次呈現(xiàn),不需要在報(bào)表中再做關(guān)聯(lián)。
類似地,MongoDB 也支持多層數(shù)據(jù),也可以用 SPL 直接計(jì)算并返回給潤乾報(bào)表。
另外數(shù)據(jù)庫還包括 NoSQL 數(shù)據(jù)庫、文件包括 HDFS 文件,對于 SPL 來講都是數(shù)據(jù)源。SPL 自有的計(jì)算能力可以使這些計(jì)算能力不一的多樣性數(shù)據(jù)獲得通用一致的計(jì)算能力。比如文件幾乎沒有計(jì)算能力,MongoDB 對 JOIN 和 GROUP 運(yùn)算支持不足,各家數(shù)據(jù)庫對窗口函數(shù)的支持程度不同、日期與字串處理能力也普遍不足且風(fēng)格迥異。采用 SPL 后可以用相對一致的方案來計(jì)算,而這將意味著更低的移植成本以及學(xué)習(xí)難度。
而且用 SPL 輔助計(jì)算后還可以保留非關(guān)系數(shù)據(jù)庫原有的優(yōu)勢。比如 MongoDB 的對追加型日志數(shù)據(jù)的吞吐能力就遠(yuǎn)遠(yuǎn)超過普通關(guān)系數(shù)據(jù)庫,但結(jié)構(gòu)化計(jì)算能力較弱,用 SPL 來彌補(bǔ)后,數(shù)據(jù)可以繼續(xù)留在 MongoDB 中,即獲得其高吞吐性能也有了結(jié)構(gòu)化計(jì)算能力。
優(yōu)化報(bào)表應(yīng)用結(jié)構(gòu)
集算器 SPL 的設(shè)計(jì)初衷是提升數(shù)據(jù)準(zhǔn)備過程的開發(fā)效率,但實(shí)際應(yīng)用下來我們發(fā)現(xiàn),SPL 不僅提升了數(shù)據(jù)準(zhǔn)備的效率,同時(shí)還優(yōu)化了應(yīng)用的結(jié)構(gòu),這個(gè)能力,也非常有意義。
·丨解釋執(zhí)行降低應(yīng)用耦合度
我們知道,JAVA 應(yīng)用大多數(shù)情況是事先編譯并靜態(tài)加載的,也就是要把所有模塊一起編譯打包后部署,在運(yùn)行過程中代碼就不再改變了。其實(shí) JAVA 也有動態(tài)編譯和加載的技術(shù),但難度和復(fù)雜度都高很多,一般應(yīng)用程序員很少使用。而且即使采用了動態(tài)加載技術(shù),也不能替換已經(jīng)加載進(jìn)內(nèi)存的類,只能不斷新增新的類。
這種機(jī)制下,用 JAVA 編寫的報(bào)表數(shù)據(jù)準(zhǔn)備算法就需要和主應(yīng)用程序一起打包發(fā)布,這會導(dǎo)致報(bào)表模塊與主應(yīng)用之間的高耦合性。
一般來講,報(bào)表的業(yè)務(wù)穩(wěn)定性要比主應(yīng)用差得多,報(bào)表變動的頻率遠(yuǎn)遠(yuǎn)高于主應(yīng)用,一旦報(bào)表的數(shù)據(jù)來源發(fā)生變化,整個(gè)應(yīng)用就得跟著重新編譯,無法做到熱切換,這種使用體驗(yàn)是很糟糕的。
如果用 SPL 來實(shí)現(xiàn)數(shù)據(jù)準(zhǔn)備算法,就能有效地降低主應(yīng)用程序與報(bào)表功能的耦合度了。
SPL 寫出來的腳本也是類似報(bào)表模板的外置文件,不需要和主應(yīng)用程序一起編譯打包,而且它是解釋執(zhí)行的動態(tài)語言,在修改時(shí)不會涉及主應(yīng)用程序,只要把 SPL 腳本替換就可以,天然就支持熱切換。
·丨算法外置減少存儲過程
在體系結(jié)構(gòu)方面用存儲過程準(zhǔn)備報(bào)表數(shù)據(jù)和用 JAVA 程序是類似的,也會造成耦合度高的問題,只是從報(bào)表模塊與主程序之間的耦合變成的報(bào)表模塊與數(shù)據(jù)庫之間的耦合。
存儲過程存放在數(shù)據(jù)庫中,報(bào)表模板放在文件系統(tǒng)中,保持兩者同步修改依然很麻煩,而且存儲過程修改時(shí)需要申請一定級別的管理員權(quán)限做重編譯,雖然不象 JAVA 那樣難以做到熱切換,但數(shù)據(jù)庫高權(quán)限的頻繁使用又會帶來安全隱患。
比 JAVA 更糟糕的是,數(shù)據(jù)庫及其中的存儲過程可能被多個(gè)應(yīng)用共享,如果管理不善,很容易造成多個(gè)應(yīng)用之間的高耦合,時(shí)間長了會搞不清楚某個(gè)存儲過程在被哪些應(yīng)用調(diào)用,越來越混亂。
同樣地,采用 SPL 也可以極大程度地減少數(shù)據(jù)庫中的存儲過程,算法外置后與報(bào)表模板一起存放管理,完全歸屬于報(bào)表模塊,不僅降低與應(yīng)用其它部分的耦合,更不會造成與其它應(yīng)用的耦合。
實(shí)際上,存儲過程本身編寫難度并不小,遍歷式計(jì)算代碼的性能也不佳,而且可移植性很差,原則上在報(bào)表業(yè)務(wù)中應(yīng)當(dāng)盡量少用存儲過程。
·丨數(shù)據(jù)外置減少中間表
數(shù)據(jù)量巨大或計(jì)算過程太復(fù)雜時(shí),我們經(jīng)常會事先對原始數(shù)據(jù)做些處理后形成中間結(jié)果,再基于這些中間結(jié)果開發(fā)報(bào)表。這些中間結(jié)果一般是以數(shù)據(jù)庫表的形式存在的,也就是這里所謂的中間表。
一個(gè)運(yùn)行時(shí)間較長的系統(tǒng)中,中間表的數(shù)量往往會遠(yuǎn)遠(yuǎn)大于原始表。某些移動公司的數(shù)據(jù)庫中有上萬個(gè)表,即使很復(fù)雜的業(yè)務(wù)用五百個(gè)表也基本能描述了,這些上萬的表中絕大多數(shù)都是為報(bào)表服務(wù)的中間表,這肯定是數(shù)據(jù)庫廠商都沒想到過的情況。
與存儲過程類似,大量的中間表也會造成數(shù)據(jù)庫管理的混亂。
數(shù)據(jù)庫中的表是以線狀方式存儲的,相當(dāng)于沒有分類,而數(shù)據(jù)庫被各個(gè)應(yīng)用共享,中間表都混到一起,很難搞清楚。這需要項(xiàng)目組有很強(qiáng)的管理控制能力才能理清,比如規(guī)定中間表的命名規(guī)則并保證得到執(zhí)行,但強(qiáng)化管理常常是以犧牲開發(fā)效率為代價(jià)的,項(xiàng)目時(shí)間一緊張就顧不得這些規(guī)矩了。
管理能力不夠好其實(shí)是常態(tài),這就會導(dǎo)致中間表越來越多,積累到上萬可能是有點(diǎn)極端,但總歸不是個(gè)小數(shù)目。這些中間表可能有相當(dāng)多已經(jīng)沒有用了,但因?yàn)椴磺宄心男?yīng)用還在使用而只能先留著,相應(yīng)的 ETL 過程也仍然要無意義地浪費(fèi)計(jì)算資源繼續(xù)更新數(shù)據(jù)。
那么為什么要把這些中間結(jié)果存到數(shù)據(jù)庫中,而不能存放到文件系統(tǒng)中呢?
這是因?yàn)槲覀儾豢赡転槊總€(gè)報(bào)表的每種參數(shù)組合事先計(jì)算中間結(jié)果,在生成報(bào)表時(shí)還需要根據(jù)參數(shù)進(jìn)行計(jì)算,也就是要求這些中間結(jié)果仍有計(jì)算能力,而目前只有數(shù)據(jù)庫有這種計(jì)算能力,文件是沒有計(jì)算能力的,于是中間數(shù)據(jù)就只能變成中間表。
中間數(shù)據(jù)一般都是由不再改變的歷史數(shù)據(jù)計(jì)算出來的,完全不需要數(shù)據(jù)庫的事務(wù)一致性能力,因?yàn)槎际菍?dǎo)出的冗余數(shù)據(jù),也不需要很高的穩(wěn)定要求,數(shù)據(jù)壞了重算一次就行了,存放在數(shù)據(jù)庫中僅僅為了獲得計(jì)算能力,實(shí)在是劃不來的。
有了 SPL 后,就可以將中間數(shù)據(jù)外置到文件系統(tǒng)中,由 SPL 提供針對文件的計(jì)算能力,可以有效地減少中間表,不必再讓這些冗余數(shù)據(jù)繼續(xù)占用昂貴并且低效的數(shù)據(jù)庫空間。
外置的中間數(shù)據(jù)文件還可以使用文件系統(tǒng)的樹形結(jié)構(gòu)管理,與報(bào)表模板及數(shù)據(jù)準(zhǔn)備算法統(tǒng)一存儲。這不僅管理簡單方便,而且,由于不考慮寫入和一致性的需求,文件還會比數(shù)據(jù)庫有更好的 IO 吞吐性能,整體提高報(bào)表的運(yùn)算速度。
·丨混合運(yùn)算實(shí)現(xiàn) T+0 報(bào)表
關(guān)系數(shù)據(jù)庫的事務(wù)一致性能力目前尚沒有有效的替代者,交易系統(tǒng)仍然有必要使用關(guān)系數(shù)據(jù)庫來建設(shè)。
這種情況下,要實(shí)現(xiàn) T+0 全數(shù)據(jù)量的實(shí)時(shí)報(bào)表,我們就得把歷史數(shù)據(jù)繼續(xù)存放在當(dāng)期的交易數(shù)據(jù)庫中一起計(jì)算,歷史數(shù)據(jù)常常要龐大得多,這會要求我們建設(shè)更大容量的數(shù)據(jù)庫,成本當(dāng)然會很高。而且即使愿意支付成本,這個(gè)數(shù)據(jù)量也不可能一直增長,太大了會影響到交易業(yè)務(wù)的性能,這就不可容忍了。
通常的辦法是把部分歷史數(shù)據(jù)被移出來做個(gè)分?jǐn)?shù)據(jù)庫,這樣可以保證交易系統(tǒng)的正常運(yùn)轉(zhuǎn),但要實(shí)現(xiàn) T+0 報(bào)表就麻煩得多,會涉及到跨庫運(yùn)算。
許多數(shù)據(jù)庫都支持跨庫運(yùn)算,但一般都要求同類型的數(shù)據(jù)庫,但歷史數(shù)據(jù)和當(dāng)期交易數(shù)據(jù)的要求不同,數(shù)據(jù)量更大但不要求事務(wù)一致性,很可能使用另一種數(shù)據(jù)倉庫來存儲。
而且,即使是同構(gòu)的數(shù)據(jù)庫,數(shù)據(jù)庫的跨庫運(yùn)算的方法一般也是將另一個(gè)庫中的數(shù)據(jù)表映射成本庫數(shù)據(jù)表,實(shí)際運(yùn)算還是一個(gè)數(shù)據(jù)庫在做,而且還多出許多數(shù)據(jù)傳遞的通訊成本,性能和穩(wěn)定性都不好。
使用 SPL 就可以很好地完成這個(gè)混合計(jì)算任務(wù)了。
SPL 自己有計(jì)算引擎,不依賴于數(shù)據(jù)庫,各個(gè)數(shù)據(jù)庫內(nèi)的數(shù)據(jù)計(jì)算仍由各庫進(jìn)行。SPL 可以使用多線程向各數(shù)據(jù)庫同時(shí)發(fā)出 SQL 語句,由這些數(shù)據(jù)庫并行執(zhí)行,將各自的運(yùn)算結(jié)果返回到 SPL 再匯總處理后傳給報(bào)表工具去呈現(xiàn)。
顯然,這種機(jī)制還方便橫向擴(kuò)展,歷史庫可以有多個(gè),是否同類型的也無所謂。
而且,SPL 還有服務(wù)器方式的集群運(yùn)行模式,在集算服務(wù)器的支持下,歷史數(shù)據(jù)不必一定存放到數(shù)據(jù)庫中,還可以存儲在 IO 性能更好的文件系統(tǒng)中,配合集群計(jì)算,可以在更低的成本下獲得更好的性能。
具體 T+0 實(shí)例可以參考:開源 SPL 輕松應(yīng)對 T+0 (http://c.raqsoft.com.cn/article/1649513370929)
提升報(bào)表運(yùn)算性能
報(bào)表的呈現(xiàn)周期中,大致可以分為下圖的 4 個(gè)環(huán)節(jié),4 個(gè)環(huán)節(jié)都有可能造成報(bào)表的性能問題,但概率較高的是前兩個(gè)環(huán)節(jié),數(shù)據(jù)準(zhǔn)備和數(shù)據(jù)傳輸(圖中黃色電池電量圖,代表了出問題的程度)。
而恰恰這兩個(gè)環(huán)節(jié)又都是報(bào)表工具無能為力的地方。
·丨提升數(shù)據(jù)準(zhǔn)備的性能
前面我們已經(jīng)說到,在數(shù)據(jù)準(zhǔn)備方面,很多場景下 SPL 比大段的 SQL,存儲過程以及 JAVA 要寫起來更容易,降低了數(shù)據(jù)準(zhǔn)備的開發(fā)難度。
事實(shí)上,SPL 不僅可以降低開發(fā)難度,還可以提升數(shù)據(jù)準(zhǔn)備的效率和性能。
我們通過一個(gè)簡單小例來看一下 SPL 比 SQL 的算法高效在哪里。
比如要在 1 億條數(shù)據(jù)中取出前 10 名,用 SQL 算就會涉及大排序,大排序就會影響性能, 其實(shí)我們是可以想出不用大排序的算法的,但 SQL 無法描述,那就只能指望數(shù)據(jù)庫優(yōu)化器了,簡單情況下,很多商用數(shù)據(jù)庫確實(shí)都能優(yōu)化,使用不必大排序的算法,性能通常也很好,但情況稍微變復(fù)雜一些,比如要在每個(gè)分組中取前 10 名,要用到窗口函數(shù)和子查詢,這時(shí)候優(yōu)化器就又無能為力了,又得乖乖去大排序,慢慢的算了。
SPL 則不然,SPL 離散數(shù)據(jù)集中有普遍集合的概念,TopN 這種運(yùn)算被認(rèn)為是和 SUM 和 COUNT 一樣的聚合運(yùn)算,只不過返回值是個(gè)集合,用 SPL 去做個(gè)這個(gè)計(jì)算的時(shí)候就不需要做大排序了。
這只是一個(gè)簡單的例子,其他的 SPL 比 SQL 性能好的高級函數(shù)還有很多。
除了新的高效的算法以外,數(shù)據(jù)的存儲對于性能也非常重要,好算法要有合適的存儲機(jī)制配合才能生效,SPL 也有自己更高效的存儲方式,高性能二進(jìn)制文件存儲,相對于普通的數(shù)據(jù)庫存儲,SPL 的二進(jìn)制存儲和 SPL 的高效算法配合,性能會更好,使用 SPL 存儲后,可以把原來需要緩存的計(jì)算過程變成不需要了,原來要遍歷多遍的運(yùn)算變成只遍歷一次甚至不用遍歷了,減少硬盤訪問量也是非常有效的性能提升手段。
報(bào)表涉及的數(shù)據(jù),基本都是歷史數(shù)據(jù),必要的時(shí)候,把這些數(shù)據(jù)換一種更高效的方式存儲,可行性也是很大的。
下面是幾個(gè)用 SPL 來優(yōu)化數(shù)據(jù)準(zhǔn)備的實(shí)際案例,有需要的可以詳細(xì)看一下:
開源 SPL 提速保險(xiǎn)公司團(tuán)保明細(xì)單查詢 2000+ 倍
開源 SPL 提速銀行資金頭寸報(bào)表 20+ 倍
開源 SPL 提速銀行 POS 機(jī)交易報(bào)表 30+ 倍
開源 SPL 提速資產(chǎn)負(fù)債表 60 倍
·丨提升數(shù)據(jù)傳輸?shù)男阅?/strong>
報(bào)表項(xiàng)目大部分都是 JAVA 應(yīng)用,基本都得通過 JDBC 來取數(shù)、做數(shù)據(jù)傳輸,有時(shí)候我們會發(fā)現(xiàn),SQL 很簡單,數(shù)據(jù)庫負(fù)擔(dān)也很輕,但數(shù)據(jù)傳輸?shù)綀?bào)表卻需要很長時(shí)間,傳輸完成后,報(bào)表也算的很快,那就可以判定,就是有些數(shù)據(jù)庫的 JDBC 取數(shù)太慢,導(dǎo)致了性能問題。
我們動不了廠商的 JDBC,那就只能曲線救國,單線程取的慢,如果數(shù)據(jù)庫允許,我們可以嘗試多線程并行取,但由于并行取數(shù)涉及的數(shù)據(jù)分段方法和數(shù)據(jù)庫及取數(shù)語法需要較復(fù)雜代碼控制,也不容易做成報(bào)表功能,所以目前的報(bào)表工具基本都不支持并行取數(shù)。
但在 SPL 中,這卻是一個(gè)非常普通的功能,下面就是一段 SPL 并行取數(shù)的代碼,寫起來還是很簡單的,也容易理解。
1=now()//記錄開始時(shí)間
2=connect("oracle").query@1x("SELECT COUNT(*) FROM CUSTOMER")
3>n=12//設(shè)置并行數(shù),根據(jù)電腦的物理CPU核數(shù)決定
4=n.(range(1,A2+1,~:n))//按總記錄數(shù)和并行數(shù)分段,記錄本段開頭和下段開頭數(shù)字
5fork A4=connect("oracle")
6=B5.query@x("SELECT * FROM CUSTOMER WHERE C_CUSTKEY>= AND C_CUSTKEY< ",A5(1),A5(2))
7=A5.conj()//合并取數(shù)結(jié)果
8=interval@s(A1,now())//計(jì)算運(yùn)行時(shí)間
在數(shù)據(jù)庫負(fù)擔(dān)不重時(shí),并行取數(shù)幾乎可以讓傳輸效率得到線性的提升。
SPL 不僅可以優(yōu)化前兩個(gè)環(huán)節(jié),對報(bào)表工具本身的計(jì)算能力也可以起到輔助提升的作用。
·丨輔助報(bào)表計(jì)算提升性能
報(bào)表內(nèi)的計(jì)算,主要得依靠報(bào)表工具的基本功,基本功好,可以保證大部分表內(nèi)計(jì)算都不出問題,但萬事總有例外,即使是以性能見長的潤乾報(bào)表,也會遇到跑不快的情況。
舉個(gè)最簡單的例子,比如要在報(bào)表里做多源關(guān)聯(lián),我們需要寫一個(gè)類似這樣的表達(dá)式 ds2.select(ID==ds1.ID),表達(dá)式很簡單,但是計(jì)算復(fù)雜度卻是平方級的,數(shù)據(jù)量不大時(shí),都沒問題,數(shù)據(jù)量稍大時(shí),到幾千行,那性能就會急劇下降了,再好的工具處理這樣的運(yùn)算也會有問題。
但如果把這個(gè)關(guān)聯(lián)放到報(bào)表外來做,用 SPL 來做,則可以使用低復(fù)雜的 HASH 算法(而在報(bào)表工具中無法對多個(gè)數(shù)據(jù)源先統(tǒng)一處理,實(shí)現(xiàn)不了這種算法),那性能就會大幅度的提升了。
以下是我們在數(shù)據(jù)量比較大時(shí),用潤乾報(bào)表單獨(dú)運(yùn)算和 SPL+ 潤乾報(bào)表協(xié)同運(yùn)算的性能對比,可以看出,報(bào)表內(nèi)的計(jì)算性能問題,如果挪到外部計(jì)算引擎解決,效果是非常好的。
(藍(lán)色是潤乾報(bào)表單獨(dú)運(yùn)算的時(shí)間,橙色是 SPL+ 潤乾報(bào)表協(xié)同運(yùn)算的時(shí)間)
另外前面提到的,有時(shí)候報(bào)表設(shè)計(jì)中會多出很多用于保存中間結(jié)果的隱藏格,這些隱藏格在計(jì)算的時(shí)候也會占用很多內(nèi)存,數(shù)據(jù)量小的時(shí)候感覺不到,量一大就卡了。
使用 SPL 去做這些過程計(jì)算,則可以避免這樣的問題。
還有緩存。
使用緩存能夠有效地改善報(bào)表響應(yīng)的用戶體驗(yàn),高端的報(bào)表工具一般都提供緩存功能。但報(bào)表工具的緩存機(jī)制比較死板,只能針對整個(gè)報(bào)表,不能只緩存報(bào)表的某個(gè)部分,兩個(gè)報(bào)表有共同部分也無法復(fù)用緩存,也沒法分別指定不同報(bào)表緩存在不同參數(shù)下的不同生存周期。因?yàn)閳?bào)表工具采用可視化的配置方案,雖然使用簡單,但很難設(shè)置過多復(fù)雜的參數(shù)。
用 SPL 準(zhǔn)備數(shù)據(jù)時(shí)就可以實(shí)現(xiàn)可控緩存的效果,SPL 是程序代碼,可以由開發(fā)者靈活決定使用緩存的時(shí)刻及范圍的策略,這樣就可以實(shí)現(xiàn)報(bào)表的部分緩存、多個(gè)報(bào)表之間緩存復(fù)用、以及不同緩存的不同生存周期。
·丨大數(shù)據(jù)量報(bào)表
報(bào)表性能問題們還有一個(gè)場景需要注意,就是大清單式報(bào)表,比如電信行業(yè),要查看當(dāng)月所有的充值記錄,這樣的報(bào)表,格式簡單,但是數(shù)據(jù)量極大,有的可達(dá)到千萬級以上,這類大數(shù)據(jù)量的報(bào)表呈現(xiàn)時(shí)如果等著把這些記錄全部檢索出來再生成報(bào)表,那會需要很長時(shí)間,用戶體驗(yàn)自然會非常惡劣,而且報(bào)表一般采用內(nèi)存運(yùn)算機(jī)制,大多數(shù)情況下內(nèi)存里也裝不下這么多數(shù)據(jù),所以我們一般都會使用分頁呈現(xiàn)的方式,盡量快速地呈現(xiàn)出第一頁,之后再通過翻頁來加載后面的。
這種分頁呈現(xiàn)的方式通常是利用數(shù)據(jù)庫的分頁機(jī)制來實(shí)現(xiàn),但數(shù)據(jù)庫分頁不僅有如下這些弊端,而且程序代碼和對應(yīng)的數(shù)據(jù)庫是強(qiáng)耦合的,萬一換了數(shù)據(jù)源,那還得重新做一遍。
更好的方式是,取數(shù)和呈現(xiàn)做成兩個(gè)異步線程,取數(shù)線程發(fā)出 SQL 后就不斷取出數(shù)據(jù)后緩存到本地存儲中,呈現(xiàn)線程根據(jù)頁數(shù)計(jì)算出行數(shù)到本地緩存中去獲取數(shù)據(jù)顯示,如下圖所示:
通過這樣的方式,就可以很好的解決大數(shù)據(jù)量清單式報(bào)表的性能難題了具體如何實(shí)現(xiàn)可以參考:大清單報(bào)表該怎么做?
總結(jié)
報(bào)表工具的兩次革命:
第一次革命,解決了國外報(bào)表工具不好用,做不了復(fù)雜報(bào)表的難題,重新定義了報(bào)表工具的標(biāo)準(zhǔn),讓用戶張口就能問:能不能做中國式復(fù)雜報(bào)表,有沒有非線性報(bào)表模型,也讓國產(chǎn)軟件在報(bào)表這個(gè)領(lǐng)域一直以碾壓式的優(yōu)勢走到現(xiàn)在。
第二次革命,解決了報(bào)表外圍的數(shù)據(jù)準(zhǔn)備過程 SQL、存儲過程、JAVA 難寫以及性能低下的難題,同時(shí)還優(yōu)化了報(bào)表應(yīng)用的結(jié)構(gòu),再一次重新定義了報(bào)表工具的標(biāo)準(zhǔn),讓業(yè)界都認(rèn)可報(bào)表工具要有一個(gè)計(jì)算層,也讓整個(gè)報(bào)表的解決方案更完整,有了質(zhì)的提升。
來源:數(shù)據(jù)猿
刷新相關(guān)文章
我要評論
不容錯(cuò)過的資訊
-
19月15日,與領(lǐng)健悅?cè)莨餐_啟醫(yī)美機(jī)構(gòu)增
-
2以數(shù)為基,恒生電子賦能量化交易數(shù)智升級
-
3聚焦服貿(mào)會| 天下秀攜旗下多項(xiàng)科技產(chǎn)品
-
4智譜AI“全球?qū)W科人才大數(shù)據(jù)平臺”榮獲20
-
5HCR慧辰全新升級數(shù)據(jù)分析能力,構(gòu)建數(shù)字
-
6打造政務(wù)應(yīng)用場景新范式,金山辦公亮相服
-
7 【聚焦服貿(mào)會】金山辦公政務(wù)云文檔賦能
-
8聯(lián)想服貿(mào)會開啟元宇宙新場景 新IT技術(shù)打
-
9《機(jī)遇之城2022》報(bào)告:中心城市帶動引領(lǐng)
-
10《2022中國企業(yè)數(shù)智化轉(zhuǎn)型升級先鋒人物》
大數(shù)據(jù)企業(yè)推薦more >
大家都在搜
