優(yōu)化互斥計算
? ? ? ? 本內(nèi)容基于SQLBI官方文獻整理的簡體筆記 -- Power 零售 BI
? ? ? 本文介紹如何使用優(yōu)化:可能會導(dǎo)致查詢性能下降的互斥(相互排斥)計算的DAX表達式 卵史。
? ? ? 在以前的文章中,我們討論了變量的重要性以及如何運用其優(yōu)化IF函數(shù)模式缩功,以減少對同一表達式或度量的多次計算碍脏。 但是示绊,有些情況下斤儿,在同一表達式的不同定義分支中(比如由IF定義的多個條件結(jié)果)執(zhí)行的計算似乎很難被優(yōu)化。 例如贷岸,請考慮以下模式:
Amount := IF (<Condition>, [Credit],? [Debit])-- 如果符合條件跃闹,則計算[Credit]嵌削,否則計算[Debit]。
? ? ? 這種涉及到度量A和B的情況望艺,似乎沒有任何可能的優(yōu)化苛秕。 然而,通過考慮兩個度量A和B各自的性質(zhì):它們可能是基于某個相同基本度量的計算找默,只不過針對該度量定義了不同的篩選條件參數(shù)而產(chǎn)生不同的計算艇劫。 例如,度量A和B可以定義為:
Raw Amount :=SUM ( Transactions[Line Amount] )
Credit := CALCULATE (? [Raw Amount], Transactions[Type] = "Credit")
Debit : = CALCULATE ( [Raw Amount], Transactions[Type] = "Debit")
? ? ? 在這種情況下惩激,DAX可能會生成一個查詢計劃店煞,其中這兩種新度量均在內(nèi)部進行計算,即使在報表中實際上僅顯示其中的某一個度量(基于同一度量定義的不同度量)风钻。例如顷蟀,通過應(yīng)用篩選來確定對IF條件的持續(xù)計算聲明。
? ? ? ? 當(dāng)然骡技,在一般的簡單表達式中鸣个,DAX可能會應(yīng)用short-circuit? --直接短路式計算,從而跳過不必要的任何分支的計算哮兰。 但是毛萌,在復(fù)雜報表中,為了生成批量計算的高效查詢計劃喝滞,此優(yōu)化通常不可用。
? ? ? ? 那么膏秫,怎樣才能優(yōu)化相類似的這種表達呢右遭?
? ? ? 我們知道,編寫DAX代碼時的一個經(jīng)驗法則是:
? ? ? 先定義篩選器以篩選出計算列表缤削,然后執(zhí)行CALCULATE計算窘哈,這比針對不同的條件而編寫不同的CALCULATE語句要更方便。 因此亭敢,以前的代碼可以寫成如下:
Raw Amount :=SUM ( Transactions[Line Amount] )
Amount := VAR TransactionType = IF ( <condition>,"Credit",? "Debit"? )
RETURN
CALCULATE (? [Raw Amount], Transactions[Type] = TransactionType? )
? ? ? 雖然滚婉,在這樣一個簡單的例子中,這種編碼可能不會轉(zhuǎn)化為性能優(yōu)勢帅刀,但在一些復(fù)雜表達中让腹,該方法可能會更快远剩。 可以通過測試兩種方法在特定用例上的性能來驗證。
? ? ? 但是骇窍,這種技術(shù)會帶來兩個額外的挑戰(zhàn):
? ? (1)使用不同變量在多個步驟中分割計算會更困難瓜晤;
? ? (2)使用條件語句創(chuàng)建適當(dāng)?shù)倪^濾器可能更復(fù)雜。
? ? ? 展示這種優(yōu)化的好處的一個常見例子是:顯示基于切片器選擇的時間智能度量的計算:比如定義一個元度量[Sales Amount]腹纳,以及基于該度量添加一個或多個步驟痢掠、條件之后的新度量[Smart Sales]。
? ? ? 原始[Sales Amount]度量和智能[Smart Sales]度量分別定義如下:
? ? ? Sales Amount :=
? ? ? SUMX ( Sales, Sales[Quantity] * Sales[Net Price] )
? ? ? Smart Sales := IF ( HASONEVALUE ( Period[Period] ),
? ? ? SWITCH ( VALUES ( Period[Period] ),
? ? ? "Last week",
? ? ? CALCULATE ([Sales Amount],?
? ? ? DATESINPERIOD ( 'Date'[Date], MAX ( 'Date'[Date] ),
? ? ? VALUES ( Period[Offset] ),DAY )? ),
? ? ? "Last 4 weeks",
? ? ? CALCULATE ( [Sales Amount],
? ? ? ? DATESINPERIOD (? 'Date'[Date],MAX ( 'Date'[Date] ),
? ? ? ? VALUES ( Period[Offset] ),? DAY )? ),
? ? ? "Last quarter",
? ? ? CALCULATE ( [Sales Amount],
? ? ? DATESINPERIOD ( 'Date'[Date],MAX ( 'Date'[Date] ),
? ? ? VALUES ( Period[Offset] ),DAY )),
? ? ? "MTD", CALCULATE ( [Sales Amount], DATESMTD ( 'Date'[Date] ) ),
? ? ? "QTD",? CALCULATE ( [Sales Amount], DATESQTD ( 'Date'[Date] ) ),
? ? ? "YTD",? CALCULATE ( [Sales Amount], DATESYTD ( 'Date'[Date] ) ), BLANK()? ))
? ? ? ? 該公式中 Swith的多個結(jié)果引用的是同一CaⅠculate條件嘲恍。 Period--周期表包含每個時間段的period列的period? type—周期類型的定義足画。 在這一列中,“D”表示從所選時間段的最后一天開始的日期范圍佃牛,“I”表示必須根據(jù)時間段名稱(MTD淹辞, QTD,YTD)在特定時間智能函數(shù)中轉(zhuǎn)換的時間段吁脱。這里唯一可見的列是Period(其他參數(shù)列為隱式)桑涎,它是上圖切片器中使用的列:
? ? ? ? 通過定義變量作為Date表的篩選器,你可以只使用單個CALCULATE來重寫[Smart Sales]--智能銷售度量兼贡。 試想攻冷,倘若能夠使用SWITCH函數(shù)來創(chuàng)建該篩器表達式,這當(dāng)然不失為一個好辦法遍希,但遺憾的是:IF和SWITCH都返回標(biāo)量值而不是表格等曼。 因此不可能編寫下面的語法:
VAR FilterDates = (前面[Smart Sales]度量公式中,從SWITCH開始的部分)
? ? ? ? 由于IF與SWITCH無法返回表凿蒜,因此禁谦,可以使用它們定義計算所需的日期范圍,并將該時期范圍篩選傳遞給單個DATESBETWEEN函數(shù)废封。 一種可能的實現(xiàn)方式是以下度量:
? ? ? 簡體注:該公式是使用變量來定義篩選器書寫DAX步驟的又一個案例州泊。其中變量FirstDaySelected需要具備一定的DAX內(nèi)部引擎知識。
? ? ? ? [Smart Sales New]度量可能有更好的性能漂洋。當(dāng)然遥皂,構(gòu)建DAX篩選器需要額外的成本,但這可能比定義不同的CALCULATE語句更有效刽漂。在本文所示的包含不同[Smart Sales]度量的小樣本數(shù)據(jù)文件中演训,這種差異并不明顯。然而贝咙,這種技術(shù)在更大的數(shù)據(jù)庫中會產(chǎn)生較大的影響样悟,因為這種類型的數(shù)據(jù)庫不容易復(fù)制和下載。
? ? ? 像往常一樣,了解DAX中解決問題的不同方法總是一個好習(xí)慣窟她。實際上陈症,性能可能會因需求的具體細節(jié)和數(shù)據(jù)分發(fā)的不同而有所不同。
? ? ? ? 當(dāng)出現(xiàn)性能問題時礁苗,在沒有可用的特殊方式(如考慮索引或聚合優(yōu)化)來解決問題時爬凑。 有必要通過更改DAX代碼以獲得更好的執(zhí)行計劃。