Power Query中的合並(或用SQL術語來說是聯接)表是刷新性能問題的常見原因。我們經常想知道是否可以采取任何措施來優化不可折疊數據源的合並性能,因此我們運行一些測試以嘗試回答所遇到的問題。在這一系列文章中,將告訴你一些發現。
對於這些測試,使用的唯一數據源是具有一百萬行和七個數字列(分別為A,B C,D,E,F和G)的CSV文件:
使用SQL Server Profiler來衡量執行查詢所花費的時間。實際上有兩個Profiler事件,它們在評估刷新性能時的持續時間很重要:
• 進度報告結束/ 25執行SQL
• 進度報告結束/ 17讀取數據
事實證明,這兩個事件提供了一些有關Power Query引擎中如何處理某些轉換的見解,但我們稍后會介紹。
第一個問題是:表中的列數是否會影響合並的性能?
首先,創建兩個相同的查詢,分別稱為First和Second,它們連接到CSV文件,使用文件中的第一行作為標題,並將所有七個列的數據類型設置為Whole Number。沒什么特別的,這里的M代碼都一樣:
let
Source = Csv.Document(
File.Contents("C:\NumbersMoreColumns.csv"),
[Delimiter = ",", Columns = 7,
Encoding = 65001, QuoteStyle = QuoteStyle.None]
),
#"Promoted Headers" =
Table.PromoteHeaders(Source, [PromoteAllScalars = true]),
#"Changed Type" = Table.TransformColumnTypes(
#"Promoted Headers",
{
{"A", Int64.Type},
{"B", Int64.Type},
{"C", Int64.Type},
{"D", Int64.Type},
{"E", Int64.Type},
{"F", Int64.Type},
{"G", Int64.Type}
}
)
in
#"Changed Type"
我們禁用這些查詢,好方便我們不將其加載到數據集中。
接下來,創建第三個查詢,該查詢使用Table.NestedJoin函數通過內部聯接合並來自這兩個查詢的數據,並返回來自兩個源查詢的所有列:
let
Source = Table.NestedJoin(
First, {"A"}, Second, {"A"},
"Second", JoinKind.Inner),
#"Expanded Second" = Table.ExpandTableColumn(
Source,
"Second",
{"A", "B", "C", "D", "E", "F", "G"},
{"Second.A", "Second.B", "Second.C",
"Second.D", "Second.E", "Second.F", "Second.G"}
)
in
#"Expanded Second"
當刷新此查詢時,在事件探查器中,上面提到的兩個事件的持續時間如下:
• 進度報告結束/ 25執行SQL – 40秒
• 進度報告結束/ 17讀取數據– 56秒
很慢,但是,當你將兩個表合並為一個列而不是七個列時,性能如何?
為了測試這一點,在“第一”和“第二”查詢中來添加一個額外的步驟,刪除了除A列(合並所需的列)之外的所有列,如下所示:
let
Source = Csv.Document(
File.Contents("C:\NumbersMoreColumns.csv"),
[Delimiter = ",", Columns = 7,
Encoding = 65001, QuoteStyle = QuoteStyle.None]
),
#"Promoted Headers" =
Table.PromoteHeaders(Source, [PromoteAllScalars = true]),
#"Changed Type" = Table.TransformColumnTypes(
#"Promoted Headers",
{
{"A", Int64.Type},
{"B", Int64.Type},
{"C", Int64.Type},
{"D", Int64.Type},
{"E", Int64.Type},
{"F", Int64.Type},
{"G", Int64.Type}
}
),
#"Removed Other Columns" =
Table.SelectColumns(#"Changed Type", {"A"})
in
#"Removed Other Columns"
然后,更新包含合並的第三個查詢以反映此更改:
let
Source = Table.NestedJoin(
First, {"A"}, Second, {"A"},
"Second", JoinKind.Inner),
#"Expanded Second" =
Table.ExpandTableColumn(Source, "Second", {"A"}, {"Second.A"})
in
#"Expanded Second"
刷新此查詢后,Profiler顯示以下持續時間:
• 進度報告結束/ 25執行SQL – 9秒
• 進度報告結束/ 17讀取數據– 1秒
這個查詢要快得多,但是后來我們想到:如果性能更多地取決於查詢返回的表的大小而不是合並的結果呢?因此,我們在合並查詢的末尾添加了一個額外的步驟,如下所示:
let
Source = Table.NestedJoin(
First, {"A"}, Second, {"A"},
"Second", JoinKind.Inner),
#"Expanded Second" =
Table.ExpandTableColumn(Source, "Second", {"A"}, {"Second.A"}),
#"Counted Rows" = Table.RowCount(#"Expanded Second")
in
#"Counted Rows"
然后重新執行上述兩個測試。我們的想法是,現在合並查詢僅返回單個值,查詢返回的數據量不應成為查詢持續時間的因素。
以下是在表中有七列的版本進行合並的時間:
• 進度報告結束/ 25執行SQL – 56秒
• 進度報告結束/ 17讀取數據– 0秒
以下是僅在一列上進行表合並的版本的時間:
• 進度報告結束/ 25執行SQL – 14秒
• 進度報告結束/ 17讀取數據– 0秒
這似乎確實可以確認表中的列數會影響合並的性能,盡管當然,對具有更多列的表中的行進行計數可能需要更長的時間。
這也顯示了其他情況:與前兩個測試相比,讀取數據在兩種情況下都是即時的,而前兩個測試花費的時間比Execute SQL事件要長。
為什么列數會影響合並的性能?合並必須在內存中進行,因此,可以猜想合並中涉及的表越大,則需要的內存就越多,如果發生以下情況,則分頁就越多,超過了256MB的限制。查看針對最后兩個查詢生成的性能計數器數據,結果發現上述兩個最后兩個查詢的確超出了256MB的限制,但是,將具有兩列的表連接到該版本的最大提交為584MB,該版本的最大提交用七個列加入表的空間幾乎為3GB。
總而言之,至少可以這樣說:
在Power Query中合並兩個表之前,刪除所有不需要的列將提高刷新性能。
推薦閱讀
技術交流
1.Power BI免費下載:http://www.yeacer.com/
Microsoft Power BI Desktop中文最新版:下載地址
2.歡迎加入的Power BI技術群,目前正在學習階段,有興趣的朋友可以一起學習討論。
Power Data技術交流群:702966126 (驗證注明:博客園Power BI)
更多精彩內容請關注微信公眾號:悅策PowerBI
如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力!歡迎各位轉載。