配置单元:按 "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
我有一个按日期分区的大型 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