2016-07-19 40 views
0

我收到一個java.lang.OutOfMemoryError:在Hive中超出了GC開銷限制。在搜索中,我發現這是因爲該進程的所有CPU時間中有98%會進行垃圾回收(無論這意味着什麼?)。我的問題是我的問題的核心?我是否應該以不同的方式寫下以避免這種問題?更高效的查詢以避免Hive中的OutOfMemoryError

我在嘗試計算特定時間段內某個手機類型有多少個活動的「使用」。有沒有辦法以不同的方式做這個邏輯,那會更好?

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 

謝謝

回答

2

一切都取決於您的數據。如果你的數據集包含的行數太多而且具有相同的imei,那麼在連接之前應用distinct就比在連接之後應用count(distinct)要好(在這種情況下你寫的是正確的)。反之亦然:如果有相同的imei重複行數很少,那麼你可以先加入它們。在加入它們之前對每個數據集應用截然不同的想法可能會更慢,這取決於您的數據。我會建議通過to_date(timestamp)字段(yyyy-mm-dd)對數據集進行分區,以便根據where子句進行分區修剪(檢查它的工作原理)。如果數據集太大並且包含大量數據(事件<>'使用'),則還通過事件字段進行分區。

重要的是要知道它在哪個階段失敗。研究例外情況。如果它在映射器上失敗,那麼你應該優化你的子查詢(按我提到的添加分區)。如果它在reducer(join)上失敗,那麼你應該以某種方式改進連接(嘗試減少字節每個reducer - set hive.exec.reducers.bytes.per.reducer=67108864;或甚至更少),如果它在寫入器上失敗(OrcWriter然後嘗試添加分區到輸出表由subsime從imei分發和substr(imei...)在查詢結束時減少減壓器的壓力)

+0

謝謝,這一直非常有幫助。我能夠在以後運行相同的查詢而沒有問題?那麼這可能是由於其他人在服務器上運行了很多查詢嗎? –

+0

嗯......'超出GC上限'意味着你的應用程序98%試圖釋放內存,而不是做一些有用的工作。也許這是因爲沒有更多的可用內存可供分配,因爲所有內存都已被其他進程使用。無論如何,這是一個擔心它的原因。也可以嘗試爲應用程序分配更多內存。看到這個:https://blogs.msdn.microsoft.com/shanyu/2014/07/31/hadoop-yarn-memory-settings-in-hdinsight/如果沒有什麼可以優化的話就做吧。 – leftjoin

3

爲了提高性能,通過查看查詢:我想先yyyy, mm, dd分區蜂巢表,或通過imei前兩個數字,你將不得不根據變量來決定你需要查詢這些表格和數據量。但我會投票給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%'; 

嘗試運行兩個查詢並比較結果。請讓我們知道這些差異,如果您覺得這有幫助。