第一節、 從細節入手
盡量不用select * from
FineReport報表的數據集采用的是表模型,也就是說通過SQL這種DSL語言,從數據庫通過簡單查詢或各種組合關聯查詢得到一個關系表,而這部分SQL查詢根據各種數據庫產商長時間的優化(比如建立索引),已經非常成熟。而這些表結構數據集一般要通過FineReport報表模型的復雜處理才能生成最終的表樣。因此,從數據庫sql查詢取出數據量越少,FineReport報表模型需要做的復雜處理和計算就越少,所化的時間和內存就少了,從而可以提高性能表現。
sql初學者剛開始時往往會忽略sql的寫法細節。然而sql優化卻是性能優化中十分關鍵的一點,有時候sql優化的好的話,可以大大提高性能。比如slect * from table1這種寫法,就比較粗糙,沒有經過優化,在數量不是很大時或許沒問題,但是如果數據量很大的話,此處就是一個很好的優化點。
如上圖所示,初級用戶經常直接拖拽表名,點菜單后就沒有再做處理,這在某些性能敏感的報表中是個不好的習慣。例如報表中只需要用到三個字段,但是數據庫中實際的表有十個字段,一些初學者習慣性的用select * from table1,這樣相當于把十個字段的數據都取到報表服務器端,增加了報表服務器端的內存占用以及減慢了運算速度
正確的寫法是:select col1,col2,col3 from table1,即用到哪幾個字段就取哪幾個,用不著的不要取。從重要的細節入手,有時候會帶來很好效果。
對于匯總類型的報表,往往需要進行分組聚集運算,如果在數據庫中先進行一次分組聚集,能夠大大減少取到報表服務器的記錄數,加快取數和報表運算的速度。
看如下報表:
這是一個典型的交叉分組報表,其sql有兩種寫法:
第一種:SELECT Region, Product, Amount FROM sale
第二種:SELECT Region, Product, sum(Amount) FROM sale group by Region, Product
而報表的做法都一樣,如下圖所示:
優化分析:
第一種做法,不僅僅取到報表服務器上記錄數多了,取數速度慢,而且報表模型需要對表數據列進行分組運算,增加了報表運行時間;
第二種做法,數據庫雖然要進行分組運算,但是數據庫中有索引,運算速度快,且取到報表服務器端的記錄數大大減少,取數速度大大加快,因此在報表模型進行分組運算的時候只要對很少的記錄數進行,報表的運算速度大大加快了。
實驗結果以及分析表明,第二種做法的性能遠優于第一種。所以,分組應該盡量在sql里進行。
跟分組同樣的道理,報表中往往需要對數據進行排序,排序運算可以在數據庫中進行,也可以在報表端進行,如果報表中的排序規則是確定的,那么建議排序操作選擇在數據庫端進行,因為數據庫中有索引,通常是C/C++語言(往往在效率上比Java好)寫的,數據運算速度快。下面以一個簡單的分組報表為例:
如果排序是在sql里面進行,則sql里面寫SELECT Manager, Product, Amount FROM sale order by Manager,如下:
報表的做法,也很簡單,直接拖拽數據列,設置格式,如下:
這樣做時,數據集ds1中對Manager數據列已經排好了序,所以報表模型不需要對數據列做任何處理,并且取數時是順序的從數據集中依次從上倒下取數,只需遍歷一遍,從而節省了時間,優化了性能。
如果排序不在sql中進行
則需要在數據列Manager的高級面板中對排序進行設定,設為升序
所以,從實驗結果可以看出,排序在sql里進行是個優化性能的好辦法。
這個問題和分組及排序是類似的,報表很多時候并不需要對表中的所有記錄進行操作,而是對部分滿足條件的記錄進行操作,因此建議過濾操作在數據庫中進行,這樣取到報表服務器端的記錄數大大減少,既加快了取數的速度,也加快了報表的運算速度,因為報表需要處理的數據少了。
依然那銷售記錄表舉例:
如果我們要取Amount超過300的記錄,在sql中寫SELECT Manager, Product, Amount FROM sale where Amount > 300
如下圖:
如果不在sql里面進行過濾,則需要在數據列的過濾面板中進行設置,如下
直接在sql中過濾,要比在數據列過濾面板中設置過濾,效率高很多。所以,考慮到性能,盡量在sql中進行過濾。