20200803 PowerBI DAX 性能優化 高級視圖算法 性能提升成千上萬倍

小伙伴催更了。準備放大招,所以,很多內容停滯了。如果本文的技巧讓您震撼,那如果告訴您,本文僅僅是開胃菜呢。開始吹吧。

此前,有很多伙伴反映 PowerBI DAX 在進行某種運算時,速度隨元素的增長會變得很慢,這個問題在很多重要的模型中都存在,包括了:

  • 帕累托分析,當要計算的元素很多時;
  • 累計百分比分析,當要計算的元素很多時;
  • 其他模型。

本文先立足給出一種對比,后續文章再研究其他案例。

問題重述

已知用戶列表,以及用戶所產生的明細數據。顯示:在動態篩選的界面中,給出用戶列表以及對應的指標積累百分比。

先從效果看來理解這個問題,如下:

image

這非常容易理解,對于每個用戶,用戶Id表示該用戶的唯一性;KPI表示該用戶的某種指標;KPI%(≤Current)表示比當前元素(包括當前元素)的KPI值低的所有元素的KPI的積累百分比。

這非常像帕累托分析,在帕累托分析中,只不過是≥當前元素的積累百分比。

數據模型

用以下精簡的數據模型來表示這個問題,有:

image

這一模型非常容易構建或模擬。

如果模擬這一數據模型,可以這樣操作:

Item = 
SELECTCOLUMNS( GENERATESERIES( 1 , 10 ) , "Id" , [Value] )

其中,10表示元素個人,也可以替換為100,1000,10000,100000,1000000來逐步觀察隨著元素個數的增加,算法的用時成本。

對于明細數據,可以這樣虛擬如下:

Detail = 
GENERATEALL( 'Item' , VAR X = RANDBETWEEN( 100 , 200 ) RETURN GENERATESERIES( X , X + RANDBETWEEN( 10 , 50 ) ) )

該模擬生成算法的意圖為,對于每個元素,都從100到200之間隨機給定一個數,并生成以該種子為起點的50個隨機條目。

常規算法

熟悉 DAX 的伙伴或分析師很快就可以寫出該問題的解法,如下:

Item.Percent%.ModelMethod = 
VAR vCurr = [Item.Value]
VAR tItemsAllSelected    = ALLSELECTED( 'Item'[Id] )
VAR tItemsFiltered       = FILTER( tItemsAllSelected , [Item.Value] <= vCurr )
RETURN COUNTROWS( tItemsFiltered ) / COUNTROWS( tItemsAllSelected )

我們稱這一算法為模型算法,而其中的[Item.Value]度量值可以認為是通用指標計算的邏輯。

模型算法用時分析

對元素個數不斷增加,可以發現在元素個數為8000的時候,算法需要消耗約15秒時間。(會因硬件配置有所不同)

這可以理解為:

如果有8000個用戶以及明細數據,需要得到這樣的積累占比分析,需要等待至少15秒鐘,考慮到其他相關可視化圖表的用時,這是無法接受的。

但這個算法,似乎已經是最好的了。在模型算法中,它使用了 VAR 暫存了數據,但似乎沒有什么卵用啊。

于是,要如何進行優化呢?

答案是:在模型層面,是無法優化的。

該算法已經使用了相當正確的寫法,并沒有明顯的問題,無法得到優化。

另辟蹊徑:視圖層算法

這里先給出結果,后面再做分析。

前面之所以叫模型算法,是針對這里要提出的視圖(層)算法相對而言的。

什么是視圖層算法?

如果計算不需要觸碰底層數據模型,而僅僅需要在視圖層面計算,我們說,這就叫視圖算法。本例中,可以這樣構造:

Item.Percent%.ViewMethod = 
VAR vCurr = [Item.Value]
VAR tView = CALCULATETABLE(
    ADDCOLUMNS( 
        VALUES( 'Item'[Id] ) , 
        "Value" , [Item.Value]
    )
    , ALLSELECTED( )
)
RETURN COUNTROWS( FILTER( tView , [Value] <= vCurr ) ) / COUNTROWS( tView )

關于視圖層算法,我們已經在此前文章中給出過詳細說明,這里不再贅述其原理。

值得一提的是,PowerBI 并不內置支持視圖層計算,而由 SQLBI 發起的針對此特性的 PowerBI 社區投票得到非常多支持,但這個特性是否支持,以及如果支持后如何實現,對于微軟的 PowerBI 團隊,其實是一個難題。

但不管 PowerBI 是否原生支持,通過我們給出的幾個案例,具有舉一反三能力的伙伴應該已經發現自助實現視圖層可視化計算的要領,這個要領幾乎是呼之欲出的,我們將在后續文章給出開創性的實現思路以及通用做法。

在這里,我們稱此處算法為視圖層算法,我們檢測其時間消耗成本,從實驗看出,它比模型算法提升了性能,但并不顯著。

視圖層索引表算法

由于我們發現視圖層算法相比模型層算法有加速的效用,我們只需要舉一反三地構建所有可能的算法并進行比對就可以選擇最優的模式。索引,顯然是一個方向,這里直接給出其實現,如下:

Item.Percent%.IndexedViewMethod = 
VAR vCurr = [Item.Value]
VAR tView = CALCULATETABLE(
    ADDCOLUMNS( 
        VALUES( 'Item'[Id] ) , 
        "Value" , [Item.Value]
    )
    , ALLSELECTED( )
)
VAR tViewWithIndex = ADDCOLUMNS( tView , "Index1" , [Value] , "Index2" , [Id] )
VAR tIndexTable = DISTINCT( SELECTCOLUMNS( tViewWithIndex , "Index1" , [Index1] , "Index2" , [Index2] ) )
VAR tIndexedView = SUBSTITUTEWITHINDEX( tViewWithIndex , "Index" , tIndexTable , [Index1] , ASC , [Index2] , ASC )
RETURN ( MAXX( FILTER( tIndexedView , [Value] = vCurr ) , [Index] ) + 1 ) / COUNTROWS( tView )

可以看出,該算法是基于視圖層算法改進而來的,對于 DAX 經驗有限的伙伴,可能有理解的難度,但這并不是本文的重點,為了全面,我們把這一算法記錄在案。通過對比,我們發現,該算法可以顯著提升性能,如下:

image

隨著元素數據的增加,IndexedView 算法可以有非常明顯的性能改善,計算 10000 元素僅需 0.5 秒,比普通的模型算法提升了近 50 倍性能,這太神奇了。更值得驚訝的是,視圖層索引表算法的編寫比常規模型算法復雜得多,但卻有超過 50 倍的性能提升,不可謂不兇殘。

如果觀察性能趨勢圖,普通的模型算法和視圖層算法都近乎是指數級時間增加,這是我們不希望的。而視圖層索引算法相對而言就平緩得多了。

視圖層排序算法

是否還可以更進一步來加速這個算法呢?答案是肯定的。

我們巧妙地利用排序的性質,為每一個元素都進行排序,那么排序的序號正是它超過元素的個數。而這個排序僅僅需要在視圖層完成計算,根本不需要觸碰模型層,給出算法如下:

Item.Percent%.RankedViewMethod = 
VAR vCurr = [Item.Value]
VAR tView = CALCULATETABLE(
    ADDCOLUMNS( 
        VALUES( 'Item'[Id] ) , 
        "Value" , [Item.Value]
    )
    , ALLSELECTED( )
)
RETURN RANKX( tView , [Value] , vCurr , ASC , Skip ) / COUNTROWS( tView )

該算法非常簡單,可以看出這也是基于視圖層計算而進行的改進。我們來看看這個算法的時間消耗趨勢,如下:

image

其效果是驚人的震撼,它面對100萬元素的300萬明細數據,僅僅需要不到3秒就可以計算完畢,在計算2萬元素節點時,其性能是經典算法的上千倍。經過測試,對100萬元素以及25億明細數據,其計算用時約為3秒。

這可以從性能面板得到各種算法時間的對比,如下:

image

總結

本文拋開了傳統的模型層算法,對于同一問題的解決,給出了視圖層的等效算法,并將性能提升上千倍,這幾乎是不可想象的。你如果問為什么會提升這么多性能,這里當然是觸發了 DAX 最快計算的竅門,限于篇幅和復雜性,就不再展開,畢竟對于 99% 的伙伴,需要的永遠是復雜和粘貼。如果你要問這是如何想到的,那必須歸功于兩點:其一,是對 DAX 本質的理解;其二,是發散思維。

然而,即使是提升了數千倍的性能,本文卻還只是開胃菜,大餐正在烹飪中。

對于希望徹底理解 DAX 本質精髓的伙伴,羅叔準備了前所未有的 VIP 線下課程,徹底揭示 PowerBI 尤其是 DAX 的本質精髓。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372