hive:按“max(partitioned_col)”过滤而不执行全表扫描

Posted

技术标签:

【中文标题】hive:按“max(partitioned_col)”过滤而不执行全表扫描【英文标题】:hive: filter by "max(partitioned_col)" without performing full table scan 【发布时间】:2015-08-13 18:05:29 【问题描述】:

我有一个按日期分区的大型 Hive 表,我正在尝试设置一个 Oozie 工作流,该工作流在最近的分区上运行一个进程。每次 ETL 作业运行时都会创建一个新文件夹。目录结构如下:

/user/hive/warehouse/my_transactions/date=20150424
[...]
/user/hive/warehouse/my_transactions/date=20150811
/user/hive/warehouse/my_transactions/date=20150812
/user/hive/warehouse/my_transactions/date=20150813

在我的家庭/实验室集群上,运行 Hive 1.1.0-cdh5.4.4,我可以在子查询中使用 max 聚合函数来过滤最近几天的数据:

select
  [...]
from my_transactions
inner join (select max(date) as max_date from my_transactions) max_date
on date = max_date

结果很快就返回了。

在我们的工作环境中,在具有更强大硬件的更大数据集上运行 Hive 0.13.0-mapr-1501,相同的查询尝试在多个阶段执行并最终抛出 java.lang.OutOfMemoryError: Java heap space

如果我用文字替换子查询,即WHERE date = '20150813',而不是聚合和内部连接,它执行得非常快。对于聚合/子查询,它似乎不是使用分区来减少 IO 量,而是尝试扫描所有分区。

是否有更好的方法来编写此查询(例如,可能查询 Hive 元数据以获取分区列的 max(date))?

【问题讨论】:

【参考方案1】:

您是否对查询运行了 EXPLAIN,以了解 Hive 如何尝试将该 JOIN 转换为子任务?

好吧,EXPLAIN 输出是一团糟,但我怀疑它会显示一个尴尬的查询计划,例如......

整个左侧表转储到每个 Mapper 的 RAM(即 Java HashMap)中 然后依次读取 右侧 子查询(1 条记录)的结果,以将每条记录与 HashMap 进行匹配

这是典型的 MAPJOIN 顺序错误。 那么,用更明确的WHERE IN (subquery) 即supported at last in Hive 0.13 替换那个虚拟的JOIN 怎么样?

底线:Hive 查询优化器仍然是一头粗暴而凶恶的野兽。在许多情况下,您必须将其引导至“正确”的查询计划。

【讨论】:

【参考方案2】:

这个查询给出了最大值(分区列)而不扫描整个表。

hive -e "set hive.cli.print.header=false;show partitions table_name;" | tail -1 | cut -d'=' -f2

【讨论】:

如何将此值提供给从另一个程序(例如 HUE)执行的查询?据我了解,这将再次需要某种自定义值注入。 是的..您必须通过这种方法通过 shell 脚本使用值注入。

以上是关于hive:按“max(partitioned_col)”过滤而不执行全表扫描的主要内容,如果未能解决你的问题,请参考以下文章

Hive 按字母排序

hive:按“max(partitioned_col)”过滤而不执行全表扫描

按 Hive 中的列分组

在 Hive 和 Presto 中按分组聚合字符串并按顺序排序

如何使用 Hive 在 Dart 中按值(而不是按索引)读取/更新/删除?

Hive - Parquet 格式 - OR 子句在未按预期工作的地方