這兩天在SparkSQL Core看到一個優化規則:OptimizeMetadataOnlyQuery,它的意思是如果一個sql只涉及表的分區字段元信息查詢的話,執行過程將不會路由到TableScanExec的PhysicalPlan進行表掃描,而是通過分區元信息的字段和值構建LocalRelation,進而構造一個LocalTable,走LocalTableScanExec的PhysicalPlan。
這個規則的觸發要滿足下面幾個條件:
- sql中所有查詢的字段必須是分區字段
- 如果使用了聚合函數,必須滿足下面條件:
- 聚合表達式是分區字段,如(col等為tbl的分區字段,下同):
SELECT col FROM tbl GROUP BY col. - 對分區字段使用的聚合函數帶Distinct,如:
SELECT count(DISTINCT col) FROM tbl GROUP BY col. - 對分區字段使用的聚合函數為Max,Min,First、Last函數,如:
SELECT Max(col) FROM tbl GROUP BY col.
- 聚合表達式是分區字段,如(col等為tbl的分區字段,下同):
如果滿足上面的條件,將會對邏輯計劃進行優化,調用replaceTableScanWithPartitionMetadata,做的事情包括:
1. 把CatalogTable中的分區字段取出來;
2. 把CatalogTable中的分區值取出來;
3. 構建LocalRelation(partAttrs, partitionData)
簡單來說,就是把分區字段及其值取出來,構造一個本地表,這樣在執行時就不需要去掃描真正的表了。
如果要禁用該優化,需要設置參數spark.sql.optimizer.metadataOnly=false
,spark里面默認是true。