應用程式效能最佳化
簡介
對於中小型 QlikView 應用程式而言,通常無需太過煩惱應用程式在效能方面的設計。但隨著資料量的成長,如果應用程式設計不良,則時間和記憶體兩者的限制就會變得非常明顯。不過,在設計上做一些簡單的更改就可能會大幅改善效能。本附錄指出一些常見的錯誤,並提出修正建議。
通常透過將「問題」從應用程式物件移到指令碼驅動資料庫,就可改善效能。但往往是無法兩全其美的情況。回應時間會改善,但臨機操作功能會降低。以下的建議不應視為對全體都有助益。當這些建議可改善應用程式的一般狀態,或可造成影響到成敗關鍵的差異時,才使用這些建議。
以下列出處理上述問題的應用方法範例。它們是用於闡述問題並指出實用的 QlikView 功能。至於哪一個才是最好的方法,並無法給予籠統的建議,但可參考範例列出的順序進行。
If ( Condition(Text),....)
牽涉到文字比較的 If 子句通常高度耗費資源。解決辦法是將文字對應為數字,例如,透過使用 autonumber (請參閱上一節中的範例) 和/或在指令碼中執行測試。
文字字串的測試比數值測試來得慢。看看以下的運算式:
If (Alfa= ‘ABC’, ‘ABC’, left (Alfa, 2))
此測試可直接在指令碼中執行,而不會喪失任何彈性。
載入
*,
If (Alfa = ‘ABC’, 1, 0) as Flag
resident table_1 ;
運算式會變成:
If ( Flag = 1,’ABC’, left (Alfa, 2))
且測試變得簡單多了。
Sum ( If (Condition, ‘FieldName’…))
此處的彙總與表格維度無關,然後將結果分散到表格的維度。若要處理此問題,可以在指令碼中進行測試,然後在表格中彙總,或者是在指令碼中執行整個操作。許多技巧都可以達成此目的,例如 interval match、group by、peek、if....then....else。
這個情況需要兩個步驟,也就是「條件」的測試和結果的彙總。以上述範例而言,如果加上彙總
Sum ( If (Alfa= ‘ABC’, Num*1.25 , Num) )
載入
*,
If (Alfa = ‘ABC’, 1, 0) as Flag
resident table_1 ;
運算式會變成
Sum ( If ( Flag = 1, Num* 1.25 , Num ) )
彙總也可直接在指令碼中執行,如下所示︰
table_2:
載入
*,
If (Alfa = ‘ABC’, 1, 0) as Flag
resident table_1 ;
table_3:
載入
Alfa,
If ( Flag = 1, Num* 1.25 , Num ) as NewNum
resident table_2 ;
table_4:
載入
Alfa,
Sum( NewNum ) as SumNum
resident table_3
group by 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()))
及
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“)
可以將巨集設定為透過應用程式中發生的任何事件來觸發。請小心串聯或遞迴事件,因為只要一觸發這類事件,就會接連觸發下一個事件。