【问题标题】:Why is my parquet partitioned data slower than non-partitioned one?为什么我的 parquet 分区数据比未分区的数据慢?
【发布时间】:2018-09-21 10:30:43
【问题描述】:

我的理解是:如果我将我的数据分区在一个列上,我将通过它查询应该更快。但是,当我尝试它时,它似乎更慢,而不是为什么?

我有一个用户数据框,我尝试对 yearmonth 进行分区而不是。

所以我有 1 个由 creation_yearmonth 分区的数据集。

questionsCleanedDf.repartition("creation_yearmonth") \
    .write.partitionBy('creation_yearmonth') \
    .parquet('wasb://.../parquet/questions.parquet')

我还有一个没有分区

questionsCleanedDf \
    .write \
    .parquet('wasb://.../parquet/questions_nopartition.parquet')

然后我尝试从这 2 个 parquet 文件创建一个数据框并运行相同的查询

questionsDf = spark.read.parquet('wasb://.../parquet/questions.parquet')

questionsDf = spark.read.parquet('wasb://.../parquet/questions_nopartition.parquet')

查询

spark.sql("""
    SELECT * FROM questions
    WHERE creation_yearmonth = 201606
""")

似乎没有分区的一个始终更快或具有相似的时间(~2 - 3s),而分区的一个稍微慢一些(~3 - 4s)。

我试着解释一下:

对于分区数据集:

== Physical Plan ==
*FileScan parquet [id#6404,title#6405,tags#6406,owner_user_id#6407,accepted_answer_id#6408,view_count#6409,answer_count#6410,comment_count#6411,creation_date#6412,favorite_count#6413,creation_yearmonth#6414] Batched: false, Format: Parquet, Location: InMemoryFileIndex[wasb://data@cs4225.blob.core.windows.net/parquet/questions.parquet], PartitionCount: 1, PartitionFilters: [isnotnull(creation_yearmonth#6414), (creation_yearmonth#6414 = 201606)], PushedFilters: [], ReadSchema: struct<id:int,title:string,tags:array<string>,owner_user_id:int,accepted_answer_id:int,view_count...

PartitionCount: 1 我应该既然在这种情况下,它可以直接去分区它应该更快?

对于非分区的:

== Physical Plan ==
*Project [id#6440, title#6441, tags#6442, owner_user_id#6443, accepted_answer_id#6444, view_count#6445, answer_count#6446, comment_count#6447, creation_date#6448, favorite_count#6449, creation_yearmonth#6450]
+- *Filter (isnotnull(creation_yearmonth#6450) && (creation_yearmonth#6450 = 201606))
   +- *FileScan parquet [id#6440,title#6441,tags#6442,owner_user_id#6443,accepted_answer_id#6444,view_count#6445,answer_count#6446,comment_count#6447,creation_date#6448,favorite_count#6449,creation_yearmonth#6450] Batched: false, Format: Parquet, Location: InMemoryFileIndex[wasb://data@cs4225.blob.core.windows.net/parquet/questions_nopartition.parquet], PartitionFilters: [], PushedFilters: [IsNotNull(creation_yearmonth), EqualTo(creation_yearmonth,201606)], ReadSchema: struct<id:int,title:string,tags:array<string>,owner_user_id:int,accepted_answer_id:int,view_count...

也很意外。起初,数据集的日期是字符串,所以我需要进行如下查询:

spark.sql("""
    SELECT * FROM questions
    WHERE CAST(creation_date AS date) BETWEEN '2017-06-01' AND '2017-07-01'
""").show(20, False)

我预计这会更慢,但事实证明,它的性能最好 ~1-2s。这是为什么?我想在这种情况下,它需要转换每一行吗?

这里的解释输出:

== Physical Plan ==
*Project [id#6521, title#6522, tags#6523, owner_user_id#6524, accepted_answer_id#6525, view_count#6526, answer_count#6527, comment_count#6528, creation_date#6529, favorite_count#6530]
+- *Filter ((isnotnull(creation_date#6529) && (cast(cast(creation_date#6529 as date) as string) >= 2017-06-01)) && (cast(cast(creation_date#6529 as date) as string) <= 2017-07-01))
   +- *FileScan parquet [id#6521,title#6522,tags#6523,owner_user_id#6524,accepted_answer_id#6525,view_count#6526,answer_count#6527,comment_count#6528,creation_date#6529,favorite_count#6530] Batched: false, Format: Parquet, Location: InMemoryFileIndex[wasb://data@cs4225.blob.core.windows.net/filtered/questions.parquet], PartitionFilters: [], PushedFilters: [IsNotNull(creation_date)], ReadSchema: struct<id:string,title:string,tags:array<string>,owner_user_id:string,accepted_answer_id:string,v...

【问题讨论】:

  • 您没有展示如何对这段代码进行基准测试,因此甚至不清楚这些值代表什么。但仅看看对象存储的范围和差异,我猜大部分时间都花在扫描“文件系统”上,读取元数据和数据不足以进行有意义的基准测试。
  • @user6910411 我正在使用 HDInsight/Jupyter Notebook,我似乎无法使用 %time 功能......所以我大致手动计时。关于文件大小,您可能是对的……每个镶木地板文件约为 10-60MB。即使没有适当的基准测试,它似乎也能提供一致但出乎意料的性能
  • parquet 中的总数据集大小只有 900MB,如果这很重要的话
  • 900 对于有用的基准测试来说太低了(大约 8 个核心足以完全覆盖所有数据)。即使您手动测量时间,也很高兴知道您测量的是什么(show 在这里没有用处)。
  • 两种情况下的分区数是多少? (questionsDf.rdd.getNumPartitions())。

标签: apache-spark parquet


【解决方案1】:

过度分区实际上会降低性能:

如果一列只有几行匹配每个值,则 要处理的目录可能成为限制因素,而数据文件 在每个目录中可能太小而无法利用 Hadoop 以兆字节块传输数据的机制。

此摘录摘自另一个 Hadoop 组件Impala 的文档,但所提供的参数应该对 Hadoop 堆栈的所有组件都有效。

我认为无论使用哪种分区方案,分区的优势在表增长到超过 900 MB-s 之前都不会明显。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-09
    • 2021-08-09
    • 2016-04-28
    • 2019-09-12
    • 1970-01-01
    相关资源
    最近更新 更多