1

如果我有一个使用多级分区创建的表,即由两列(州、市)组成,如下所示:

    state=CA,city=Anaheim
    state=Texas,city=Houston
    state=Texas,city=Dallas
    state=Texas,city=Austin
    state=CA,city=SanDiego

如果我运行这样的选择查询:

select * from table_name where city=Houston

即在哪里使用了第二个分区列,它会扫描city=Houston分区state=Texas吗?我很确定这就是 Hive 的运作方式,但我很想确认 Spark 中的行为。此外,如果它在 EMR 的 Spark 中执行,行为会有什么不同吗?

4

2 回答 2

0

如果您使用 hive 存储表,那么它肯定能够对外部和内部分区进行分区修剪。Hive 单独保存有关表的分区信息的元数据。因此,当查询针对特定分区时,它能够进行优化。

您实际上可以使用以下方法测试此行为explain select * from table_name where city ='Houston';

但是,如果您使用 spark 以嵌套结构编写分区,那么我不太确定。如果查询需要遍历整个目录结构,当目录数量巨大时,这将是昂贵的。

于 2019-11-12T07:56:47.010 回答
0

让我们从从文件路径与元存储加载数据的情况开始。在这种情况下,Spark 将首先执行递归文件列表以发现嵌套的分区文件夹和其中的文件。然后将分区文件夹定义为用于分区修剪的字段。因此,在您过滤任何分区列的情况下,Spark 将仅选择满足该谓词的分区。您可以通过在查询中使用该explain方法来确认。请注意以下PartitionCount: 1

scala> input1.where("city = 'Houston'").explain()
== Physical Plan ==
*(1) FileScan parquet [id#32,state#33,city#34] Batched: true, Format: Parquet, Location: InMemoryFileIndex[file:/tmp/data], PartitionCount: 1, PartitionFilters: [isnotnull(city#34), (city#34 = Houston)], PushedFilters: [], ReadSchema: struct<id:int>

将其与没有任何过滤器的查询计划进行比较,其中PartitionCount: 5

scala> input1.explain()
== Physical Plan ==
*(1) FileScan parquet [id#55,state#56,city#57] Batched: true, Format: Parquet, Location: InMemoryFileIndex[file:/tmp/data], PartitionCount: 5, PartitionFilters: [], PushedFilters: [], ReadSchema: struct<id:int>

现在第二种情况是加载分区表时。在这种情况下,分区由 Hive 管理,因此可以节省昂贵的递归文件列表。当您过滤分区列时,Spark 将再次仅选择相关分区。请注意以下explain计划:

scala> input2.where("city = 'Houston'").explain()
== Physical Plan ==
*(1) FileScan parquet default.data[id#39,state#40,city#41] Batched: true, Format: Parquet, Location: PrunedInMemoryFileIndex[file:/tmp/data/state=Texas/city=Houston], PartitionCount: 1, PartitionFilters: [isnotnull(city#41), (city#41 = Houston)], PushedFilters: [], ReadSchema: struct<id:int>
于 2019-11-13T03:09:10.673 回答