【问题标题】:Performance tuning a Hive query性能调整 Hive 查询
【发布时间】:2012-07-08 23:25:54
【问题描述】:

我有一个 Hive 查询,它选择大约 30 列和大约 400,000 条记录并将它们插入到另一个表中。我的 SQL 子句中有一个连接,它只是一个内部连接。

由于超出 Java GC 开销限制,查询失败。

奇怪的是,如果我删除 join 子句,只从表中选择数据(体积略大),那么查询就可以正常工作。

我对 Hive 还是很陌生。我不明白为什么这个连接会导致内存异常。

关于如何编写 Hive 查询,我是否应该注意一些事项,以免它们引起这些问题?谁能解释一下为什么加入可能会导致这个问题,但选择更多的数据量和相同的列数却不会。

感谢您对此的看法。 谢谢

【问题讨论】:

    标签: performance exception memory hive


    【解决方案1】:

    根据 Hive 的版本和您的配置,您的问题的答案可能会有所不同。 如果您可以共享您的确切查询以及两个表的创建语句和它们的大小估计值会更容易。

    为了更好地理解这个问题,让我们来看看 Hive 中的“常规”内部连接是如何工作的。

    Hive 加入 MapReduce:

    以下是 Hive 中的内部连接如何编译为 MapReduce 的简化描述。一般来说,如果您有两个表 t1 和 t2 并带有如下连接查询:

    SELECT
       t1.key, t1.value, t2.value
    FROM
       t1
       JOIN
       t2 (ON t1.key = t2.key);
    

    其中,t1有以下内容:

    k_1    v1_1
    k_2    v1_2
    k_3    v1_3    
    

    其中,t2有如下内容:

    k_2    v2_2
    k_3    v2_3
    k_4    v2_4    
    

    我们希望连接结果是

    k_2    v1_2    v2_2
    k_3    v1_3    v2_3
    

    假设表存储在 HDFS 上,它们的内容将被拆分为文件拆分。映射器将文件拆分作为输入,并发出作为表的键列的键和作为表的值列和标志的组合的值(表示记录来自哪个表,即 t1 或 t2) .

    对于 t1:

    k_1, <v1_1, t1>
    k_2, <v1_2, t1>
    k_3, <v1_3, t1>
    

    对于 t2:

    k_2, <v2_2, t2>
    k_3, <v2_3, t2>
    k_4, <v2_4, t2>
    

    现在,这些发出的记录会经过 shuffle 阶段,其中所有具有相同键的记录被组合在一起并发送到 reducer。每个 reduce 操作的上下文是一个键和一个包含与该键对应的所有值的列表。在实践中,一个 reducer 会执行多个 reduce 操作。

    在上面的例子中,我们会得到以下分组:

    k_1, <<v1_1, t1>>
    k_2, <<v1_2, t1>, <v2_2, t2>>
    k_3, <<v1_3, t1>, <v2_3, t2>>
    k_4, <<v2_4, t2>>
    

    这是减速器中发生的事情。对于值列表中的每个值,如果这些值对应于不同的表,reducer 将执行乘法运算。

    对于 k_1,t2 没有任何值,也没有发出任何内容。

    对于 k_2,发出值的乘积 - k_2、v1_2、v2_2(因为每个表都有一个值,1x1 = 1)

    对于 k_3,发出值的乘积 - k_3、v1_3、v2_3(因为每个表都有一个值,1x1 = 1)

    对于 k_4,t1 没有任何值,也没有发出任何内容。 因此,您从内部联接中获得了预期的结果。

    好的,那我该怎么办?

    1. 您的数据可能存在偏差。换句话说,当reducer获取数据时,某个key对应的value列表很长,导致出错。 为了缓解这个问题,您可以尝试增加 JVM 可用的内存。您可以通过在 hive-site.xml 中将 mapred.child.java.opts 设置为 -Xmx512M 之类的值来实现。您可以通过在 Hive shell 中执行 set mapred.child.java.opts; 来查询此参数的当前值。

    2. 您可以尝试使用“常规”连接的替代方法,例如地图加入。以上对连接的解释适用于连接发生在减速器中的常规连接。根据您使用的 Hive 版本,Hive 可能会自动将常规连接转换为更快的映射连接(因为连接发生在映射阶段)。要启用优化,请将hive.auto.convert.join 设置为true。这个属性是在Hive 0.7

    3. 中引入的
    4. 除了将hive.auto.convert.join 设置为true,您还可以将hive.optimize.skewjoin 设置为true。这将解决 1 中描述的数据偏差问题。

    【讨论】:

      【解决方案2】:

      非常感谢马克的回复。非常感谢。

      经过几个小时后,我最终发现 join 语句中的表顺序有所不同。为了获得最佳性能和内存管理,最后一个连接应该是最大的表。

      在 join 语句中更改表的顺序解决了这个问题。

      http://hive.apache.org/docs/r0.9.0/language_manual/joins.html查看最后一个最大的表

      您上面的解释也非常有用。非常感谢

      【讨论】:

      • 嘿,如果你同意 Mark Grover 的解决方案,你应该“接受”他的回答,而不是接受自己的解决方案,这并不是真正的解决方案,而是对正确答案的欣赏。
      • +1 对上述评论。但我认为,由于他是 SO 新手,他可能没有意识到这里的工作原理。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多