配置单元:按“max(partitioned_col)”过滤而不执行全表扫描

时间:2015-08-13 18:05:29

标签: hive hiveql

我有一个按日期分区的大型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))?

2 个答案:

答案 0 :(得分:2)

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

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

  • 整个左侧表转储到每个Mapper的RAM(即Java HashMap)中
  • 然后按顺序读取右侧子查询(1条记录)的结果,以便根据HashMap匹配每条记录

这是典型的错误顺序的MAPJOIN。 那么,用supported at last in Hive 0.13更明确的JOIN取代虚假WHERE IN (subquery)呢?

底线:Hive查询优化器仍然是一个粗暴恶毒的野兽。在许多情况下,你必须把它引导到"纠正"查询计划。

答案 1 :(得分:0)

此查询提供max(分区列)而不扫描整个表。

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