【问题标题】:More efficient query to avoid OutOfMemoryError in Hive更有效的查询以避免 Hive 中的 OutOfMemoryError
【发布时间】:2016-07-19 21:25:46
【问题描述】:

我在 Hive 中遇到了一个异常:

java.lang.OutOfMemoryError: 超出 GC 开销限制。

在搜索中,我发现这是因为进程的所有 CPU 时间的 98% 都将用于垃圾收集(无论这意味着什么?)。我的问题的核心是我的查询吗?我应该以不同的方式编写以下内容以避免此类问题吗?

我正在尝试计算在给定时间段内有多少特定手机类型具有有效的“使用”功能。有没有办法以不同的方式执行这个逻辑,这样会更好地运行?

select count(a.imei)
from
(Select distinct imei
from pingdata
where timestamp between TO_DATE("2016-06-01") AND TO_DATE("2016-07-17")
and ((SUBSTR(imei,12,2) = "04") or (SUBSTR(imei,12,2) = "05")) ) a
join
(SELECT distinct imei
FROM eventdata
where timestamp between TO_DATE("2016-06-01") AND TO_DATE("2016-07-17")
AND event = "Use" AND clientversion like '3.2%') b
on a.imei=b.imei

谢谢

【问题讨论】:

    标签: performance hadoop hive out-of-memory memory-efficient


    【解决方案1】:

    在加入之前对每个数据集应用 distinct 更安全,因为加入非唯一键会重复数据。

    我建议通过 to_date(timestamp) 字段 (yyyy-MM-dd) 对您的数据集进行分区,以便根据您的 where 子句进行分区修剪(检查它是否有效)。如果数据集太大并且包含大量事件“使用”的数据,也可以按事件字段进行分区。

    重要的是要知道它在哪个阶段失败。研究异常。如果它在映射器上失败,那么您应该优化您的子查询(如我所述添加分区)。如果它在reducer(join)上失败,那么你应该以某种方式改进join(尝试减少每个reducer的字节数:

    set hive.exec.reducers.bytes.per.reducer=67108864; 甚至更少)如果它在 writer 上失败(OrcWriter 然后尝试通过 imei 的 substr 将分区添加到输出表,并在查询结束时通过 substr(imei ...) 分配以减少压力减速机)。

    或者添加更多低基数且分布均匀的列,以在多个reducer之间均匀分布数据:

    distribute by substr(imei...), col2
    

    确保分区列在分发者中。这将减少每个reducer写入的文件数量,并有助于摆脱OOM

    【讨论】:

    • 谢谢,这很有帮助。我能够在以后运行相同的查询而没有问题吗?那么这是否可能只是由于其他人也在服务器上运行了大量查询?
    • Hmm...“超出 GC 开销限制”意味着您的应用程序 98% 试图释放内存而不是做一些有用的工作。也许是因为没有更多的空闲内存可以分配,因为所有内存都已被其他进程使用。无论如何,这是担心它的理由。此外,您可以尝试为您的应用程序分配更多内存。看到这个:blogs.msdn.microsoft.com/shanyu/2014/07/31/…如果没有什么可以优化的就去做吧。
    【解决方案2】:

    为了提高性能,通过查看您的查询:我将按yyyy, mm, ddimei 的前两位数字对配置单元表进行分区,您必须根据查询这些的需要来决定变量表和数据量。但我会投票给yyyy, mm, dd,这会给你带来巨大的性能提升。见improving-query-performance-using-partitioning

    但是现在,这应该会给你一些改进:

    Select count(distinct(pd.imei))
    from pingdata pd join eventdata ed on pd.imei=ed.imei
    where 
    TO_DATE(pd.timestamp) between '2016-06-01' AND '2016-07-17'
    and pd.timestamp=ed.pd.timestamp
    and SUBSTR(pd.imei,12,2) in ('04','05') 
    and ed.event = 'Use' AND ed.clientversion like '3.2%';
    

    如果TO_DATE(timestamp) 值是在同一天插入的,换句话说,如果日期的两个值相同,则应排除and pd.timestamp=ed.pd.timestamp 条件。

    Select count(distinct(pd.imei))
    from pingdata pd join eventdata ed on pd.imei=ed.imei
    where 
    TO_DATE(pd.timestamp) between '2016-06-01' AND '2016-07-17'
    and SUBSTR(pd.imei,12,2) in ('04','05') 
    and ed.event = 'Use' AND ed.clientversion like '3.2%';
    

    尝试运行这两个查询并比较结果。如果您觉得这有帮助,请告诉我们其中的区别。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-05
      • 1970-01-01
      • 2017-03-20
      • 1970-01-01
      相关资源
      最近更新 更多