这两天在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。