Databricks中的显式表分区如何影响写入性能?

Jes*_*ano 5 hive amazon-s3 apache-spark-sql databricks delta-lake

我们有以下场景:

  • 我们有一个包含约的现有表.150亿条记录.它没有在创建时明确分区.
  • 我们正在使用分区创建此表的副本,希望在某些类型的查询上更快地读取时间.
  • 我们的表位于Databricks Cloud,我们使用Databricks Delta.
  • 我们通常按两列过滤,其中一列是实体的ID(350k个不同的值),其中一列是事件发生的日期(到目前为止31个不同的值,但每天都在增加!).

因此,在创建新表时,我们运行了这样的查询:

CREATE TABLE the_new_table
USING DELTA
PARTITIONED BY (entity_id, date)
AS SELECT
  entity_id,
  another_id,
  from_unixtime(timestamp) AS timestamp,
  CAST(from_unixtime(timestamp) AS DATE) AS date
FROM the_old_table
Run Code Online (Sandbox Code Playgroud)

此查询已运行48小时并计数.我们知道它正在取得进展,因为我们在相关的S3前缀中发现了大约250k前缀对应于第一个分区键,并且前缀中肯定存在一些大文件.

但是,我们在确切地监控已取得多少进展以及我们可以期待多长时间方面遇到一些困难.

在我们等待的时候,我们尝试了这样的查询:

CREATE TABLE a_test_table (
  entity_id STRING,
  another_id STRING,
  timestamp TIMESTAMP,
  date DATE
)
USING DELTA
PARTITIONED BY (date);

INSERT INTO a_test_table
SELECT
  entity_id,
  another_id,
  from_unixtime(timestamp) AS timestamp,
  CAST(from_unixtime(timestamp) AS DATE) AS date
FROM the_old_table
  WHERE CAST(from_unixtime(timestamp) AS DATE) = '2018-12-01'
Run Code Online (Sandbox Code Playgroud)

请注意,新表模式的主要区别在于我们仅在日期而不是在实体ID上进行分区.我们选择的日期几乎只占旧表数据的4%,我想指出这一点,因为它远远超过1/31.当然,因为我们选择的是一个恰好与我们分区相同的单个值,所以我们实际上只编写了一个分区,而大概是十万分左右.

使用相同数量的工作节点创建此测试表需要16分钟,因此我们可以预期(基于此)创建一个大25倍的表只需要大约7个小时.

这个答案似乎部分承认使用太多分区可能会导致问题,但是在过去几年中,潜在原因似乎发生了很大变化,因此我们试图了解当前的问题可能是什么.在Databricks文档没有特别的照明.

根据S3发布的请求率指南,似乎增加分区(密钥前缀)的数量应该可以提高性能.有害的分区似乎违反直觉.

总结:我们期望在数千个分区中的每一个中写入数千条记录.看来减少分区数会大大减少写表数据所需的时间.为什么这是真的?是否有关于为特定大小的数据创建的分区数量的一般指导原则?

hla*_*gos 3

我根本不是数据块专家,但希望这些要点可以有所帮助

分区数量

无论如何,创建的分区和文件的数量都会影响作业的性能,特别是使用 s3 作为数据存储,但是这个数量的文件应该可以通过下降大小的集群轻松处理

动态分区

通过 2 个键而不是一个键进行动态分区之间存在巨大差异,让我尝试更详细地解决这个问题。

当您动态分区数据时,根据任务数量和数据大小,每个分区可能会创建大量小文件,这可能(并且可能会)影响需要使用此数据的下一个作业的性能,特别是当您的数据以 ORC、parquet 或任何其他柱状格式存储时。请注意,这仅需要仅地图作业

前面解释的问题可以通过不同的方式解决,最常见的是文件合并。为此,数据被重新分区,目的是创建更大的文件。因此,需要对数据进行混洗。

您的疑问

对于您的第一个查询,分区的数量将为 350k*31(大约 11MM!),考虑到处理作业所需的洗牌量和任务量,这确实很大。

对于第二个查询(仅需要 16 分钟),所需的任务数量和所需的洗牌要小得多。

分区的数量(洗牌/排序/任务调度/等)和作业执行的时间不存在线性关系,这就是为什么在这种情况下数学不会相加。

推荐

我想你已经明白了,你应该将你的 etl 作业分成 31 个不同的查询,这将允许优化执行时间