我有一个Hive查询,它选择了大约30列和大约400,000条记录并将它们插入到另一个表中。我在SQL子句中有一个连接,它只是一个内连接。
由于超出了Java GC开销限制,查询失败。
奇怪的是,如果我删除了join子句并只选择表中的数据(稍高的音量),那么查询工作正常。
我对Hive很新。我无法理解为什么这个连接导致内存异常。
关于如何编写Hive查询以便它们不会导致这些问题,我是否应该注意一些事项?任何人都可以解释为什么连接可能会导致此问题,但选择更大量的数据和相同数量的列不会。
欣赏你对此的看法。 感谢
答案 0 :(得分:35)
根据Hive的版本和您的配置,您的问题的答案可能会有所不同。 如果您可以与两个表的create语句以及它们的大小估计共享您的确切查询会更容易。
为了更好地理解这个问题,让我们来看看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上,它们的内容将被拆分为File Splits。映射器将文件拆分为输入,并将密钥作为表的键列发出,值作为表的值列和标志的复合(表示记录来自哪个表,即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>
现在,这些发出的记录经过洗牌阶段,其中所有具有相同键的记录被组合在一起并发送到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没有值,也没有发出任何值。 因此,您可以获得内部联接所期望的结果。
好的,我该怎么办?
您的数据可能存在偏差。换句话说,当reducer获取数据时,对应于某个键的值列表非常长,这会导致错误。
要解决此问题,您可以尝试增加JVM可用的内存。您可以通过在hive-site.xml中将mapred.child.java.opts
设置为-Xmx512M
之类的值来执行此操作。您可以通过在Hive shell中执行set mapred.child.java.opts;
来查询此参数的当前值。
您可以尝试使用“常规”加入的替代方法,例如地图加入。上面的连接说明适用于常规连接,其中连接发生在reducers中。根据您使用的Hive的版本,Hive可以自动将常规连接转换为更快的地图连接(因为连接发生在地图阶段)。要启用优化,请将hive.auto.convert.join
设置为true
。此属性是在Hive 0.7
除了将hive.auto.convert.join
设置为true
之外,您还可以将hive.optimize.skewjoin
设置为true
。这将解决1中描述的数据问题的偏差。
答案 1 :(得分:6)
非常感谢Mark的回应。非常感谢。
经过几个小时后,我终于发现join语句中表的顺序有所不同。为了获得最佳性能和内存管理,最后一个连接应该是最大的表。
在连接语句中更改表的顺序解决了问题。
请参阅http://hive.apache.org/docs/r0.9.0/language_manual/joins.html
上的最大表格上面的解释也很有用。非常感谢