配置单元:按 "max(partitioned_col)" 过滤而不执行完整 table 扫描

hive: filter by "max(partitioned_col)" without performing full table scan

我有一个按日期分区的大型 Hive table,我正在尝试设置一个在最新分区上运行进程的 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

在我的 home/lab 集群 运行 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' 而不是聚合和内部连接,它执行得非常快。使用 aggregation/subquery 似乎不是使用分区来减少 IO 量,而是尝试扫描所有分区。

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

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

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

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

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

底线:Hive 查询优化器仍然是一个粗鲁而恶毒的野兽。在许多情况下,您必须将其引导至 "correct" 查询计划。

此查询给出最大(分区列)而不扫描整个 table。

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