Hive查询优化

时间:2015-12-23 09:57:14

标签: performance hadoop hive hiveql

每天在源数据文件附加新记录时,必须从配置单元中的外部表执行内部表的增量加载。可以根据加载它们的时间戳(表中的load_ts列)过滤掉新记录。尝试通过从源表中选择其load_ts大于目标表中当前max(load_ts)的记录来实现此目的,如下所示:

INSERT INTO TABLE target_temp PARTITION (DATA_DT)
SELECT ms.* FROM temp_db.source_temp ms 
JOIN (select max(load_ts) max_load_ts from target_temp) mt
ON 1=1
WHERE
ms.load_ts > mt.max_load_ts;

但是上面的查询没有给出所需的输出。执行需要很长时间(不应该是 Map-Reduce范例的情况)。

尝试了其他方案,例如将max(load_ts)作为变量传递,而不是加入。性能仍然没有改善。如果有人能够通过任何替代解决方案提供他们对这种方法可能不正确的见解,将会非常有帮助。

3 个答案:

答案 0 :(得分:0)

首先,map / reduce模型并不能保证您的查询花费更少。主要思想是它的性能会随着节点的数量线性扩展,但你必须仍然考虑你的工作方式,比普通的SQL要多。

首先要检查的是 source 表是否按时间划分。如果没有,它应该像你每次都在阅读整个表格一样。 其次,您还要在整个目的地表上每次计算最大值。如果你只计算最后一个分区的最大值,你可以让它快得多,所以改变这个

JOIN (select max(load_ts) max_load_ts from target_temp) mt

到此(你没有写分区列,所以我假设它被称为'dt'

JOIN (select max(load_ts) max_load_ts from target_temp WHERE dt=PREVIOUS_DATA_DT) mt

因为我们知道max load_ts将在最后一个分区中。

否则,如果不知道源表的结构,并且像其他人评论的那样,很难提供两个表的大小。

答案 1 :(得分:0)

JOIN比WHERE子句中的变量慢。但这里的性能主要问题是您的查询执行目标表和源表的完整扫描。我建议:

  1. 仅查询max(load_ts)的最新分区。
  2. 启用统计信息收集和使用

    set hive.compute.query.using.stats=true;
    set hive.stats.fetch.column.stats=true;
    set hive.stats.fetch.partition.stats=true;
    set hive.stats.autogather=true;
    
  3. 计算列的两个表的统计信息。 统计信息将使选择MAX(分区)或max(ts)执行更快的查询

    1. 尝试将源分区文件放入目标分区文件夹而不是INSERT(如果适用)(目标和源表分区和存储格式应启用此功能)。它适用于文本文件存储格式,如果源表分区只包含行> max(target_partition)。您可以将两个复制文件方法(对于那些准确包含要插入行的源分区而不进行过滤)和INSERT(对于包含需要过滤的混合数据的分区)进行组合。

    2. Hive可能在INSERT期间合并您的文件。此合并阶段需要额外的时间并添加额外的阶段作业。检查hive.merge.mapredfiles选项并尝试将其关闭。

    3. 当然使用预先计算的变量而不是join。

答案 2 :(得分:0)

通过启用以下属性来使用基于成本的优化技术

set hive.cbo.enable=true;
set hive.stats.autogather=true;
set hive.stats.fetch.column.stats=true;
set hive.compute.query.using.stats=true;
set hive.vectorized.execution.enabled=true;
set hive.exec.parallel=true;

阿劳分析表

ANALYZE TABLE temp_db.source_temp COMPUTE STATISTICS [comma_separated_column_list];
ANALYZE TABLE target_temp PARTITION(DATA_DT) COMPUTE STATISTICS;