2017-05-31 79 views
1

我有一個簡單的火花SQL查詢:如何在執行前更改查詢計劃(可能會關閉優化)?

SELECT x, y 
FROM t1 INNER JOIN t2 ON t1.key = t2.key 
WHERE expensiveFunction(t1.key) 

expensiveFunction是火花UDF(用戶定義函數)。

當我看到火花生成的查詢計劃,我看到它有兩個過濾操作而不是隻有一個:它檢查不僅expensiveFunction(t1.key),也expensiveFunction(t2.key)

image

一般情況下,這種優化是不是一件壞事,因爲它減少的記錄加入的數量,並加入是昂貴的操作。但在我的情況下,expensiveFunction(t2.key)總是返回true,所以我想刪除它。

有沒有辦法在執行查詢之前更改查詢計劃?有沒有一種方法可以指示我不希望給定的優化應用於我的查詢?

回答

1

您可以像下面那樣重寫此查詢以避免額外的函數調用。

SELECT x, y 
FROM (SELECT <required-columns> FROM t1 WHERE expensiveFunction(t1.key)) t0 INNER JOIN t2 ON t0.key = t2.key 

要格外相信你能堅持這個查詢(SELECT FROM t1 WHERE expensiveFunction(t1.key))作爲一個單獨的數據幀。然後用此DataFrame加入表t2

例如,假設我們分別有表t1t2的DataFrames df1df2。我們執行類似以下的操作以避免撥打expensiveFunction兩次。

val df3 = df1.filter("col1 == 1") 
df3.persist() // forces evaluation of this dataframe and applies the expensive function filter on df1. 
df3.createOrReplaceTempView("t1") 
spark.sql("""SELECT t1.col1. t2.col2 
FROM t1 INNER JOIN t2 ON t1.col2 = t2.col1""") // this query now have no reference to expensiveFunction 
+0

另存爲一個單獨的數據框不起作用,我試了一下。數據框是懶惰的對象,查詢規劃者可以訪問它們的依賴關係。我打算用子查詢來嘗試它,但我認爲優化器無論如何都會看到可能的優化。 – lovasoa

+0

在單獨的數據框中,您將調用persist()方法。如果你調用的方法堅持數據幀評估是強制的,然後你可以加入這個持久數據框與其他數據框,你加入查詢將沒有提及'expensiveFunction'功能 –

+1

這是一個好主意,並且確實防止火花執行不需要的優化。但是,它會增加持續存儲大數據集的成本,然後立即讀取它...因此,如果有人知道如何直接從查詢計劃器禁用優化,我很樂意聽到它。 – lovasoa

1

有沒有辦法來改變執行查詢前查詢計劃?

一般來說,是的。 Spark SQL查詢計劃器和優化器中有幾個擴展點可以實現願望

有沒有一種方法可以指示我不想將給定的優化應用於我的查詢?

這幾乎是不可能的,除非優化允許。換句話說,你必須找出規則是否有選擇將其關閉,例如, CostBasedJoinReorderspark.sql.cbo.enabledspark.sql.cbo.joinReorder.enabled配置屬性(當時either is off CostBasedJoinReorder does nothing)。

您可以編寫一個自定義的邏輯運算符,使優化無效(因爲它不會匹配給定未知的邏輯運算符),並且在您將其移除的優化階段。使用extendedOperatorOptimizationRules註冊自定義優化。