分区
分区
什么是分区?
分区是一种在写入时将相似的行分组在一起,从而使查询更快的方式。
例如,查询 logs 表中的日志条目通常会包含一个时间范围,比如查询上午 10 点到 12 点之间的日志:
SELECT level, message FROM logs
WHERE event_time BETWEEN '2018-12-01 10:00:00' AND '2018-12-01 12:00:00';将 logs 表配置为按 event_time 的日期进行分区,会把日志事件按事件日期分组到同一个文件中。Iceberg 会记录该日期,并利用它跳过不含有效数据的其他日期的文件。
Iceberg 可以按年、月、日、小时等粒度对时间戳进行分区。它还可以使用分类列(例如本日志示例中的 level)将行存储在一起,从而加快查询速度。
Iceberg 有什么不同之处?
其他表格式(如 Hive)也支持分区,但 Iceberg 支持的是隐式分区(hidden partitioning)。
- Iceberg 负责处理为表中各行生成分区值这一繁琐且易出错的任务。
- Iceberg 会自动跳过不必要的分区。使用方无需了解表的分区方式,也不必在查询中添加额外的过滤条件。
- Iceberg 的分区布局可以按需演进。
Hive 中的分区
为了说明两者的差异,我们来看看 Hive 会如何处理 logs 表。
在 Hive 中,分区是显式的,并且会作为一个列出现,因此 logs 表会有一个名为 event_date 的列。写入时,INSERT 操作需要提供 event_date 列的数据:
INSERT INTO logs PARTITION (event_date)
SELECT level, message, event_time, format_time(event_time, 'YYYY-MM-dd')
FROM unstructured_log_source;同样,查询 logs 表时,除了 event_time 过滤条件外,还必须带有 event_date 过滤条件。
SELECT level, count(1) as count FROM logs
WHERE event_time BETWEEN '2018-12-01 10:00:00' AND '2018-12-01 12:00:00'
AND event_date = '2018-12-01';如果缺少 event_date 过滤条件,Hive 将扫描表中的每个文件,因为它不知道 event_time 列与 event_date 列之间存在关联。
Hive 分区的问题
Hive 必须由外部提供分区值。在日志示例中,它不知道 event_time 与 event_date 之间的关系。
这会导致几个问题:
Hive 无法校验分区值——是否产生正确的值完全取决于写入方
- 使用错误的格式,例如写成
2018-12-01而不是20181201,会产生静默的错误结果,而不是查询失败 - 使用错误的源列(如
processing_time)或时区,同样会导致错误结果而非失败
- 使用错误的格式,例如写成
查询是否正确完全由用户负责
- 使用错误的格式同样会导致静默的错误结果
- 不了解表物理布局的用户会得到不必要地变慢的查询——Hive 无法自动转换过滤条件
可用的查询与表的分区方案绑定在一起,因此分区配置一旦更改就会破坏查询
Iceberg 的隐藏分区
Iceberg 通过获取列值并对其(可选地)施加变换来生成分区值。将 event_time 转换为 event_date 的工作由 Iceberg 负责,并且它会记录这一关系。
表的分区就是基于这些关系进行配置的。logs 表将按 day(event_time) 和 level 进行分区。
由于 Iceberg 不需要用户维护分区列,因此可以隐藏分区。分区值每次都能被正确生成,并且在可能的情况下总是被用来加速查询。生产者和消费者甚至不会看到 event_date 的存在。
最重要的是,查询不再依赖表的物理布局。通过物理布局与逻辑布局的分离,Iceberg 表可以随着数据量的变化随时间演进分区方案。配置错误的表无需昂贵的迁移即可修复。
有关所有受支持的隐藏分区变换的详细信息,请参阅分区变换部分。
有关更新表分区规范的详细信息,请参阅分区演进部分。
评论
登录后参与评论
KnowForge