在《秒級(jí)展現(xiàn)的百萬級(jí)大清單報(bào)表怎么做》中,我們介紹了無論 RDB 還是非 RDB,潤(rùn)乾報(bào)表都能夠通過異步線程實(shí)現(xiàn)秒級(jí)海量大清單報(bào)表(以下簡(jiǎn)稱:大報(bào)表)。實(shí)際業(yè)務(wù)中,除了查詢明細(xì),有時(shí)還要展現(xiàn)全量匯總數(shù)據(jù),或者查詢分組明細(xì)和計(jì)算分組匯總。本文就將介紹這些帶有匯總和分組的大報(bào)表的開發(fā)方法。
創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括瓊山網(wǎng)站建設(shè)、瓊山網(wǎng)站制作、瓊山網(wǎng)頁制作以及瓊山網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,瓊山網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到瓊山省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
在大報(bào)表中計(jì)算匯總值與常規(guī)報(bào)表基于報(bào)表內(nèi)數(shù)據(jù)進(jìn)行的匯總不同,大報(bào)表由于采用異步線程,因此無法通過報(bào)表內(nèi)數(shù)據(jù)進(jìn)行匯總(因?yàn)槊看沃荒苋〉讲糠謹(jǐn)?shù)據(jù)),只能在數(shù)據(jù)處理階段計(jì)算匯總值并交給報(bào)表呈現(xiàn)。
我們還是使用《秒級(jí)展現(xiàn)的百萬級(jí)大清單報(bào)表怎么做》中 SQL 源大報(bào)表的例子,現(xiàn)在需要在每頁最后一行顯示訂單匯總情況(訂單數(shù)量、訂單總額、運(yùn)費(fèi)總額)。
增加一個(gè)數(shù)據(jù)集 ds2 計(jì)算匯總值:
報(bào)表中最后一行引入 ds2 匯總值進(jìn)行呈現(xiàn),這里為了每頁都包含匯總數(shù)據(jù),設(shè)置最后一行屬性為報(bào)表尾。
當(dāng)然,帶有匯總的大報(bào)表性能跟計(jì)算匯總值的 SQL 執(zhí)行效率強(qiáng)相關(guān),所以可能會(huì)發(fā)現(xiàn)帶有匯總的大報(bào)表要比單純查詢明細(xì)慢一些。
實(shí)際業(yè)務(wù)中,簡(jiǎn)單呈現(xiàn)大報(bào)表清單往往還不夠,有時(shí)還需要對(duì)海量數(shù)據(jù)進(jìn)行分組,呈現(xiàn)匯總及明細(xì)情況。下面,我們就以訂單數(shù)據(jù)為例,查詢一下按地區(qū)分組的明細(xì)及訂單金額匯總。
首先,需要呈現(xiàn)分組明細(xì)的報(bào)表無法在數(shù)據(jù)源端進(jìn)行聚合,例如通過 SQL 聚合后就不包含分組明細(xì)了,除非再查詢一次進(jìn)行拼接,但查詢兩次顯然會(huì)嚴(yán)重影響性能。因此我們需要盡量將明細(xì)數(shù)據(jù)讀出后在應(yīng)用端進(jìn)行分組聚合。
那問題就來了,由于海量數(shù)據(jù)要通過分批讀取的方法進(jìn)行呈現(xiàn),如何保證讀取的每批分組數(shù)據(jù)是完整的?如果分組數(shù)據(jù)不完整,分組聚合的結(jié)果顯然也就不正確了。因此,除了要保證能在應(yīng)用端實(shí)現(xiàn)聚合,還要保證批量讀取數(shù)據(jù)時(shí)分組數(shù)據(jù)的完整性。
下面就是潤(rùn)乾報(bào)表結(jié)合集算器(數(shù)據(jù)集)實(shí)現(xiàn)分組大報(bào)表的過程。
我們需要編寫集算器 SPL 腳本進(jìn)行數(shù)據(jù)準(zhǔn)備。這里,我們要編寫兩個(gè) SPL 腳本,分別實(shí)現(xiàn):查詢分組明細(xì)并計(jì)算匯總,以及通過游標(biāo)分批為報(bào)表返回結(jié)果集。
設(shè)置腳本參數(shù):
編寫 SPL 腳本:
A | B | C | |
1 | =connect("db") | ||
2 | =A1.cursor@x(“select 貨主地區(qū), 訂單 ID, 客戶 ID, 訂購日期, 運(yùn)貨費(fèi), 訂單金額 from 訂單 where 訂購日期 >=? and 訂購日期 <=? order by 貨主地區(qū)”,begin,end) | /建立數(shù)據(jù)庫游標(biāo)查詢訂單數(shù)據(jù),并按地區(qū)排序 | |
3 | for A2; 貨主地區(qū) | /按地區(qū)分組讀取數(shù)據(jù) | |
4 | =A3.derive(0:flag) | /增加標(biāo)志位 | |
5 | =B4.sum(訂單金額) | /分組匯總 | |
6 | >B4.insert(0,null,null,null,null,"訂單金額小計(jì):",B5,1) | /匯總值添加到明細(xì)數(shù)據(jù)中 | |
7 | return B4 | /返回明細(xì)及分組結(jié)果 |
SPL 解析:
1、 A2 查詢數(shù)據(jù)庫,SQL 中指定按照分組字段(貨主地區(qū))排序,以便后續(xù)可以每次取出整個(gè)分組進(jìn)行匯總。為此需要在排序字段上建立索引,避免全表排序時(shí)間過長(zhǎng)。
2、 A3 循環(huán)游標(biāo),以貨主地區(qū)為標(biāo)記,保證每次讀取的記錄數(shù)為一個(gè)地區(qū)數(shù)據(jù)
3、 B4 增加標(biāo)志位,用于后續(xù)報(bào)表展現(xiàn)中突出匯總行。標(biāo)志為 0 時(shí)表示是明細(xì)記錄
4、 B5 針對(duì)每個(gè)分組進(jìn)行匯總
5、 B6 將分組值追加到明細(xì)記錄中,標(biāo)志設(shè)為 1,表示是匯總記錄
6、 B7 返回分組明細(xì)和匯總集合。注意這里 return 寫在循環(huán)內(nèi),因此會(huì)多次返回分組集合
在集算器 SPL 腳本中,for cs,n;x 表示針對(duì)游標(biāo) cs 通過循環(huán)遍歷數(shù)據(jù),每輪從游標(biāo)讀取 n 條記錄或者直到記錄中的 x 發(fā)生變化,循環(huán)全部結(jié)束后關(guān)閉游標(biāo)。大數(shù)據(jù)量的分組取數(shù)是這種循環(huán)的常用之處。如果省略了 n 和 x,那就簡(jiǎn)單地返回游標(biāo)中所有數(shù)據(jù)并關(guān)閉游標(biāo)。函數(shù)的具體說明可以參考:http://doc.raqsoft.com.cn/esproc/func/forcsnx.html
當(dāng)大數(shù)據(jù)集按照分組字段有序時(shí),這種取數(shù)方式每次可以讀取一個(gè)完整分組到內(nèi)存中參與計(jì)算,不過這時(shí)仍然要求分組不能很大(內(nèi)存能裝下)。而在金融和電信行業(yè)中,經(jīng)常要基于單用戶做數(shù)據(jù)分析,也就是按用戶分組,而每個(gè)用戶的流水記錄規(guī)模又較大,常規(guī)的拆分方法作起來十分復(fù)雜。而通過集算器就可以很好地解決這類問題了。
設(shè)置腳本參數(shù):
編寫 SPL 腳本:
A | B | |
1 | =cursor("group-detail.dfx",begin,end) | /調(diào)用 dfx 生成游標(biāo) |
2 | return A1 | /為報(bào)表返回游標(biāo) |
前一個(gè) SPL 腳本 group-detail.dfx 解決了分組查詢明細(xì)并匯總計(jì)算的問題。這個(gè)腳本 main.dfx 則可以分批次取數(shù)并提供給潤(rùn)乾報(bào)表,從而實(shí)現(xiàn)異步大報(bào)表呈現(xiàn)。腳本中 A1 通過 cursor 函數(shù)直接調(diào)用前一腳本生成游標(biāo),由 A2 將游標(biāo)返回給報(bào)表。
使用 cursor 函數(shù)調(diào)用 SPL 腳本生成游標(biāo)時(shí),被調(diào)用的 SPL 腳本可以有多個(gè)返回結(jié)果集(例如在 for 循環(huán)中的多個(gè) return),而游標(biāo)取數(shù)(fetch)時(shí)可以依次使用多個(gè) return 結(jié)果,無需等待所有結(jié)果集都準(zhǔn)備好再使用,原理如下圖所示。函數(shù)的具體說明可以參考:http://doc.raqsoft.com.cn/esproc/func/cursordfx.html
結(jié)合大報(bào)表使用 cursor() 函數(shù)運(yùn)行原理
設(shè)置報(bào)表參數(shù),查詢起止日期:
設(shè)置數(shù)據(jù)集引用 main.dfx 并傳遞日期參數(shù):
按照大報(bào)表模板設(shè)計(jì)思路,編寫表達(dá)式
為了將匯總行高亮顯示出來,這里利用了數(shù)據(jù)準(zhǔn)備階段增加的標(biāo)志位 flag 列,當(dāng) flag 值為 1 的時(shí)候代表該行為匯總行,設(shè)置背景色表達(dá)式:if(A3==1,-3355444)
設(shè)置大數(shù)據(jù)集
將做好的模板發(fā)布到 WEB 端,效果如下:
當(dāng)然,標(biāo)志位 flag 列也可以設(shè)置為隱藏。
調(diào)整報(bào)表模板,將標(biāo)志位 flag 列隱藏,并設(shè)置 B3 格的擴(kuò)展屬性 同值合并為“縱向合并”
展現(xiàn)時(shí)分組列則帶有合并格的效果:
在《秒級(jí)展現(xiàn)的百萬級(jí)大清單報(bào)表怎么做》中,我們提示了大報(bào)表不要全表排序,也不適合高并發(fā)場(chǎng)景。除此以外,對(duì)于帶有分組匯總和明細(xì)的大報(bào)表還應(yīng)該注意:
由于計(jì)算分組明細(xì)和匯總值時(shí)需要將某一個(gè)分組數(shù)據(jù)全部加載到內(nèi)存中進(jìn)行計(jì)算,因此分組相對(duì)內(nèi)存容量不宜過大,從而確保單個(gè)分組數(shù)據(jù)能進(jìn)行全內(nèi)存計(jì)算。