應用程式效能最佳化

簡介

對於中小型 QlikView 應用程式而言,通常無需太過煩惱應用程式在效能方面的設計。但隨著資料量的成長,如果應用程式設計不良,則時間和記憶體兩者的限制就會變得非常明顯。不過,在設計上做一些簡單的更改就可能會大幅改善效能。本附錄指出一些常見的錯誤,並提出修正建議。

通常透過將「問題」從應用程式物件移到指令碼驅動資料庫,就可改善效能。但往往是無法兩全其美的情況。回應時間會改善,但臨機操作功能會降低。以下的建議不應視為對全體都有助益。當這些建議可改善應用程式的一般狀態,或可造成影響到成敗關鍵的差異時,才使用這些建議。

以下列出處理上述問題的應用方法範例。它們是用於闡述問題並指出實用的 QlikView 功能。至於哪一個才是最好的方法,並無法給予籠統的建議,但可參考範例列出的順序進行。

If ( Condition(Text),....)

牽涉到文字比較的 If 子句通常高度耗費資源。解決辦法是將文字對應為數字,例如,透過使用 autonumber (請參閱上一節中的範例) 和/或在指令碼中執行測試。

文字字串的測試比數值測試來得慢。看看以下的運算式

If (Alfa= ‘ABC’, ‘ABC’, left (Alfa, 2))

此測試可直接在指令碼中執行,而不會喪失任何彈性。

Load

*,

If (Alfa = ‘ABC’, 1, 0) as Flag

resident table_1 ;

運算式會變成

If ( Flag = 1,’ABC’, left (Alfa, 2))

且測試變得簡單多了。

Sum ( If (Condition, ‘FieldName’…))

此處的彙總與表格維度無關,然後將結果分散到表格的維度。若要處理此問題,可以在指令碼中進行測試,然後在表格中彙總,或者是在指令碼中執行整個操作。許多技巧都可以達成此目的,例如 interval matchgroup bypeekif....then....else

這個情況需要兩個步驟,也就是「條件」的測試和結果的彙總。以上述範例而言,如果加上彙總

Sum ( If (Alfa= ‘ABC’, Num*1.25 , Num) )

Load

*,

If (Alfa = ‘ABC’, 1, 0) as Flag

resident table_1 ;

運算式會變成

Sum ( If ( Flag = 1, Num* 1.25 , Num ) )

彙總也可直接在指令碼中執行,如下所示︰

table_2:

Load

*,

If (Alfa = ‘ABC’, 1, 0) as Flag

resident table_1 ;

table_3:

Load

Alfa,

If ( Flag = 1, Num* 1.25 , Num ) as NewNum

resident table_2 ;

 

table_4:

Load

Alfa,

Sum( NewNum ) as SumNum

resident table_3

group by Alfa ;

備註: 彙總是針對 Alfa,因為這是測試中的維度。

If ( Condition, Sum(‘FieldName’)..)

這個包含在此處的語法結構只是為了強調與前一個情況的差異。這類彙總是完全與內容相關的,而且一般來說不會造成效能上的問題。

If ( Condition1, Sum(‘FieldName’), If (Condition2, Sum(‘FieldName’)……..

巢狀 If...then else... 的邏輯在概念上很簡單,但常常會造成執行上的棘手問題。我們曾經見過不只一個有數百個巢狀層次的情況。這樣會需要大量的記憶體和 CPU。「條件」常常可以透過轉換而加以取代。一個典型的範例是彙總 quantity*price,而其中 price 為變數。這可透過「延伸間隔比對」加以處理。如果要滿足兩個條件 (例如 “A AND B”),該測試可以透過條件 “C“ 來取代。

範例:

sum((GAC12_STD_COST * GAC15_EXCHANGE_RATE) * GIV24_DISP_QTY)

Replaces

Sum(

If((GAC12_EFCT_DT<= GIV23_REJ_DT and

GAC12_EXPIRE_DT>GIV23_REJ_DT) and

(GAC15_EFCT_DT<= GIV23_REJ_DT and GAC15_EXPIRE_DT>GIV23_REJ_DT),

GAC12_STD_COST * GAC15_EXCHANGE_RATE) * GIV24_DISP_QTY,

Null()))

and

Sum(

If(GAC12_EFCT_DT<= GIV23_REJ_DT,

If(GAC12_EXPIRE_DT>GIV23_REJ_DT,

If(GAC15_EFCT_DT<= GIV23_REJ_DT,

If(GAC15_EXPIRE_DT>GIV23_REJ_DT,

(GAC12_STD_COST * GAC15_EXCHANGE_RATE) * GIV24_DISP_QTY,

Null())))))

透過讀取欄位 GAC12_STD_COST 和 GAC15_EXCHANGE_RATE 為緩慢變更的維度。

請參閱: 使用延伸 intervalmatch 語法解決維度緩慢變化的問題

排序文字

QlikView 會自動評估要以數值文字通用格式來處理某個欄位。評估為文字的欄位會視為文字加以排序,而這是最緩慢的排序操作。這可手動取代為按載入順序來排序。如果並不需要對列表框等加以排序,可關閉排序功能。

QlikView 會將混合字元和數字的字串,以英數字元的順序加以排序。也就是說,數字是以值順序排序,非數字則是以 ASCII 順序排序,而非傳統上僅使用 ACII 排序順序。範例:

ASCII 排序 英數字元排序
A1 A1
A10 A4
A11 A5
A30 A6
A4 A10
A5 A11
A6 A30

動態標題和文字物件

可以輸入文字的地方幾乎都可以輸入動態計算的運算式。但評估運算式所需的資源則取決於其環境。圖表和表格中定義於運算式對話方塊中的運算式,僅在物件可見且資料變更時才會進行計算。例如當物件最小化時,這類運算式不會進行計算。

不過,如果物件標題是計算而得的,則每次有任何變更發生,就會執行該計算。另外還有許多定義顯示條件、計算條件等等的方式,這些測試也會每次都執行。

部分運算式比起其他運算式更耗費資源,而且這些運算式越常需要評估,就會變得越耗費資源。而導入非同步計算則改變了這種行為,而且這些影響可能在您的應用程式中變得越來越顯著。

時間函數 (例如 Now()Today()) 會在每次需要重新計算時進行評估。尤其 Now() 函數會變得高度耗費資源,因為它會造成應用程式每秒都重新計算。

例如︰

If ( ReloadTime()+3>Now(), 'Old Data', 'New Data')

可考慮使用

If ( ReloadTime()+3>Today(), 'Old Data', 'New Data')

在此做個簡單的測試︰將該運算式置於文字方塊中,然後嘗試在包含 Now() 的時候調整文字方塊的大小。

巨集觸發程序 (“on change“)

可以將巨集設定為透過應用程式中發生的任何事件來觸發。請小心串聯或遞迴事件,因為只要一觸發這類事件,就會接連觸發下一個事件。