通常狀況下,若是報表中存在不少格間計算(即單元格之間的關聯計算),那麼一般會影響報表性能。這是由於:sql
一、格間計算很難分步驟編寫,致使運算過程很難優化。數據庫
二、格間計算可能須要屢次遍歷單元格集才能完成運算。性能
三、格間計算每每要利用較多隱藏格做爲中間變量。而隱藏格除格值外,還記錄了不少與顯示相關的屬性值,好比:字體、顏色、顯示方式等。即使設置了單元格隱藏,但這些屬性還在,依然會佔用內存,影響計算速度。字體
不過在潤乾報表的集算腳本支持下,這個問題可以獲得很好的解決。下面咱們就經過一個典型的例子——《僱員銷售狀況排名》報表,來看下傳統方式和潤乾報表的對比:優化
報表要求以下:設計
按照員工姓名排序,根據訂單總價計算排名,而且計算「和上一名的差距」。blog
1、傳統實現方式排序
一、首先定義 sql 數據集 ds1,其 sql 以下:內存
SELECT EMPLOYEE.EID,MAX(EMPLOYEE.NAME) 姓名,sum(訂單明細. 數量 * 訂單明細. 單價) 訂單總價 FROM EMPLOYEE, 訂單, 訂單明細 WHERE 訂單. 訂單 ID = 訂單明細. 訂單 ID AND EMPLOYEE.EID = 訂單. 僱員 ID group by EMPLOYEE.EID order by 姓名table
能夠看到,爲了讓輸出結果要按姓名排序,SQL 中要寫做「ORDER BY 姓名」。
二、報表設計
其中,
僱員姓名、訂單總價:直接來自 sql。
排名:C2 單元格利用格間計算實現排名計算。計算當前訂單總價的排名時,須要先找出全部訂單總價中比本格值大的單元格,而後符合條件的單元格數加一就是排名。也就是說每計算一個僱員的排名,就要遍歷一邊全部的訂單總價。
相似地,D2 計算「和上一名的差距」時還要再作一次按條件遍歷。這個遍歷還存在引用關係的處理,要等排名列計算完才能算差距列,但報表計算次序通常是從上到下的,中途處理引用關係會致使屢次失敗的試算(試圖計算某格,若是發現該格引用的格未計算就要存放等待着下一輪再計算),失敗的試算會浪費大量時間。
上述格間計算對訂單總價遍歷了 n 次,n 是僱員個數,兩個格間運算的整體複雜度是 2*N*N。
2、潤乾報表方案
採用潤乾報表方案(結合集算器實現),能夠編寫過程化的集算腳本代替格間計算,從而提高報表性能。
一、編寫集算器腳本
對於本報表,編寫腳本以下(保存爲 sales.dfx):
A | |
---|---|
1 | =connect(「demo」) |
2 | =A1.query(「SELECT EMPLOYEE.EID,MAX(EMPLOYEE.NAME) 姓名,sum(訂單明細. 數量 * 訂單明細. 單價) 訂單總價,null 排名,0 和上一名的差距 FROM EMPLOYEE, 訂單, 訂單明細 WHERE 訂單. 訂單 ID = 訂單明細. 訂單 ID AND EMPLOYEE.EID = 訂單. 僱員 ID group by EMPLOYEE.EID order by 訂單總價 desc」) |
3 | =A1.close() |
4 | =A2.run(#: 排名,if(#!=1, 訂單總價 [-1]- 訂單總價,0): 和上一名的差距) |
5 | =A4.sort(姓名) |
6 | return A5 |
代碼說明:
A1:鏈接數據庫。
A2:用 sql 計算訂單總價,並按照訂單總價降序排序。
A3:關閉數據庫。
A4:對 A2 循環計算,「排名」等於當前記錄的行號 #,「和上一名的差距」等於用上一行的訂單總價減去當前行的訂單總價,若是是第一行就直接爲 0。
A5:按照姓名從新排序。
A6:返回結果集給報表。
能夠看到集算腳本僅用一次遍歷加一次排序就完成了排名和上一名的差距的計算,也不存在試算以解決引用關係的問題,全部計算都能一次成功進行。本方案的總體複雜度是 N(遍歷計算)+N*logN(排序),比以前的格間計算快得多。
二、配置報表數據集
在報表設計器中定義集算數據集,調用 sales.dfx:
三、設計報表
設計表樣以下: