溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Hive中的count(distinct)如何優(yōu)化

發(fā)布時間:2021-12-10 09:17:38 來源:億速云 閱讀:510 作者:小新 欄目:大數(shù)據(jù)

這篇文章主要為大家展示了“Hive中的count(distinct)如何優(yōu)化”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Hive中的count(distinct)如何優(yōu)化”這篇文章吧。


問題描述

COUNT(DISTINCT xxx)在hive中很容易造成數(shù)據(jù)傾斜。針對這一情況,網(wǎng)上已有很多優(yōu)化方法,這里不再贅述。 
但有時,“數(shù)據(jù)傾斜”又幾乎是必然的。我們來舉個例子:

假設(shè)表detail_sdk_session中記錄了訪問某網(wǎng)站M的客戶端會話信息,即:如果用戶A打開app客戶端,則會產(chǎn)生一條會話信息記錄在該表中,該表的粒度為“一次”會話,其中每次會話都記錄了用戶的唯一標(biāo)示uuid,uuid是一個很長的字符串,假定其長度為64位?,F(xiàn)在的需求是:每天統(tǒng)計當(dāng)月的活用用戶數(shù)——“月活躍用戶數(shù)”(當(dāng)月訪問過app就為活躍用戶)。我們以2016年1月為例進行說明,now表示當(dāng)前日期。 
最簡單的方法

這個問題邏輯上很簡單,SQL也很容易寫出來,例如:

SELECT  COUNT(DISTINCT uuid)FROM detail_sdk_session tWHERE t.date >= '2016-01-01' AND t.date <= now

上述SQL代碼中,now表示當(dāng)天的日期。很容易想到,越接近月末,上面的統(tǒng)計的數(shù)據(jù)量就會越大。更重要的是,在這種情況下,“數(shù)據(jù)傾斜”是必然的,因為只有一個reducer在進行COUNT(DISTINCT uuid)的計算,所有的數(shù)據(jù)都流向唯一的一個reducer,不傾斜才怪。

 

優(yōu)化1

其實,在COUNT(DISTINCT xxx)的時候,我們可以采用“分治”的思想來解決。對于上面的例子,首先我們按照uuid的前n位進行GROUP BY,并做COUNT(DISTINCT )操作,然后再對所有的COUNT(DISTINCT)結(jié)果進行求和。 
我們先把SQL寫出來,然后再做分析。

-- 外層SELECT求和SELECT  SUM(mau_part) mauFROM(  -- 內(nèi)層SELECT分別進行COUNT(DISTINCT)計算  SELECT    substr(uuid, 1, 3) uuid_part,    COUNT(DISTINCT substr(uuid, 4)) AS mau_part  FROM detail_sdk_session  WHERE partition_date >= '2016-01-01' AND partition_date <= now  GROUP BY substr(uuid, 1, 3)) t;
 

上述SQL中,內(nèi)層SELECT根據(jù)uuid的前3位進行GROUP BY,并計算相應(yīng)的活躍用戶數(shù)COUNT(DISTINCT),外層SELECT求和,得到最終的月活躍用戶數(shù)。 
這種方法的好處在于,在不同的reducer各自進行COUNT(DISTINCT)計算,充分發(fā)揮hadoop的優(yōu)勢,然后進行求和。

注意,上面SQL中,n設(shè)為3,不應(yīng)過大。 
為什么n不應(yīng)該太大呢?我們假定uuid是由字母和數(shù)字組成的:大寫字母、小寫字母和數(shù)字,字符總數(shù)為26+26+10=62。理論上,內(nèi)層SELECT進行GROUP BY時,會有 62^n 個分組,外層SELECT就會進行 62^n 次求和。所以n不宜過大。當(dāng)然,如果數(shù)據(jù)量十分巨大,n必須充分大,才能保證內(nèi)層SELECT中的COUNT(DISTINCT)能夠計算出來,此時可以再嵌套一層SELECT,這里不再贅述。

 

優(yōu)化2

其實,很多博客中都記錄了使用GROUP BY 操作代替 COUNT(DISTINCT) 操作,但有時僅僅使用GROUP BY操作還不夠,還需要加點小技巧。 
還是先來看一下代碼:

--  第三層SELECTSELECT  SUM(s.mau_part) mauFROM(  -- 第二層SELECT  SELECT    tag,    COUNT(*) mau_part  FROM  (      -- 第一層SELECT    SELECT      uuid,       CAST(RAND() * 100 AS BIGINT) tag  -- 為去重后的uuid打上標(biāo)記,標(biāo)記為:0-100之間的整數(shù)。    FROM detail_sdk_session    WHERE partition_date >= '2016-01-01' AND partition_date <= now    GROUP BY uuid   -- 通過GROUP BY,保證去重   ) t  GROUP BY tag) s;
 
  • 第一層SELECT:對uuid進行去重,并為去重后的uuid打上整數(shù)標(biāo)記
  • 第二層SELECT:按照標(biāo)記進行分組,統(tǒng)計每個分組下uuid的個數(shù)
  • 第三層SELECT:對所有分組進行求和       
    上面這個方法最關(guān)鍵的是為每個uuid進行標(biāo)記,這樣就可以對其進行分組,分別計數(shù),最后去和。如果數(shù)據(jù)量確實很大,也可以增加分組的個數(shù)。例如:CAST(RAND() * 1000 AS BIGINT) tag

以上是“Hive中的count(distinct)如何優(yōu)化”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI