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