我们有以下场景:
- 我们有一个现有的表,其中包含大约。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
此查询已运行 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'
请注意,这里新表模式的主要区别是我们仅在日期上进行分区,而不是在实体 ID 上进行分区。我们选择的日期几乎正好包含旧表数据的 4%,我想指出这一点,因为它远远超过 1/31。当然,由于我们选择的单个值恰好与我们分区的对象相同,因此我们实际上只写了一个分区,而可能是十万左右。
使用相同数量的工作节点创建此测试表需要 16 分钟,因此我们预计(基于此)创建 25 倍大的表只需要大约7 小时。
这个答案似乎部分承认使用过多的分区会导致问题,但根本原因在过去几年中似乎发生了很大变化,因此我们试图了解当前的问题可能是什么;Databricks文档并不是特别有启发性。
根据发布的 S3 请求率指南,似乎增加分区(键前缀)的数量应该会提高性能。有害的分区似乎违反直觉。
总而言之:我们期望将数千条记录写入数千个分区中的每一个。看来,减少分区数量会大大减少写入表数据所需的时间。为什么这是真的?是否有关于应为特定大小的数据创建的分区数量的一般准则?