當前位置:首頁 » 網路資訊 » sql數據傾斜是怎樣產生的
擴展閱讀

sql數據傾斜是怎樣產生的

發布時間: 2023-05-05 05:44:36

❶ Hive數倉-數據傾斜優化

首先傾斜一般發生在rece階段

-- 解決方案

Hive默認啟動Map join 優化

如果是查詢的語句列如(group, join)可以直接在yarn kill掉
如果是 insert ,,, select 就要權衡 等他跑完

結束後 對sql語句發生數據傾斜的地方爛塵進行定位、給出解決方案、測試、變更

可以要對進行join 或者group by 的欄位采樣
列如 訂單表1000w條數據 商品表100w條數據
a.pid = b.pid

select pid ,count(*) from tb_order group by pid;
查看一下訂單表中 商品key的個數
列如商品1 900w條 那麼這個數據一定會發生數據傾斜

textfile 文本文件 hdfs 默認存儲
SequenceFile 二進制文件 使用二進制位元組碼存儲 存儲方式為行存儲,其具有使用方便、可分割、
可壓縮的特點
RCfile 、
ORCfile 列式存儲
行式存儲 方便插入 列式存儲 方便查詢
:相比TEXTFILE和SEQUENCEFILE,RCFILE由於列式存搏歲儲方式,數據載入時性基歷睜能消耗較大,但是具有較好
的壓縮比和查詢響應。
數據倉庫的特點是一次寫入、多次讀取,因此,整體來看,RCFILE相比其餘兩種格式具有較明顯的優勢

❷ 數據傾斜解決思路詳解

數慎輪據傾斜是由於某個task被分配過多數據,而比其他task需要更多的執行時間(如幾十倍,幾百倍),培伏導致其他task執行完進入漫長等待的一種現象。

數據傾斜只會發生在多對多或一對多的數據分發的過程中,如spakr的shuffle操作中,在MapRece中的rece階段,

常見的運算元類型為:join,group by 和窗口函數如row_number 。

這是因為這些運算元會進行shuffle操作,產生一個key值,如group by的欄位,join的on欄位,

為了利用多台機器的並發能力,會按這個key值取數范圍進行均衡的分發,每台機器盡量分到相同長度的取值范圍的key,

然後將這些有key值的數據的數據傳輸過去。

這時如果某個key范圍內的數據量大大多於其他范圍的數據量,就會發生數據傾斜。

解決辦法:

解決數據傾斜的思路在於,先找到產生數據傾斜的運算元操作,然後針對具體的運算元,解決它單個key范圍被分到過多的數據的問題,

按key的類型,由簡便到復雜依次有以下幾種解決思路:

1.直接消滅傾斜的key。

2.直接避免shuffle操作,沒有了shuffle操作也就沒有了數據傾斜

3.通過增多task的數量,減小單個task內的數據量,這個方法適用於某個key范圍的數據多的情況。

4.通過特殊處理key值,減小單個task內的數據量,這個方法適用於某些特定的key值的數據過多的情況

第一個解決思路比較簡單,找到傾斜的key,直接過濾掉。就沒有傾斜問題了。這種操作的適用范圍很窄。比如一些空字元串,一些預設值等等,本身在業務上能接受它們不參與操作。

如果發現造成傾斜的key是這些,就可以直接過濾,非常簡單粗暴,性價比最高。

如果該key不能被過濾,就考慮能否將shuffle操作避免掉。

比如join的時候使用廣播的方式,將其中一張表廣播到所有的機器節點上,這樣一個shuffle操作就變成了一個map操作。

廣播的方式(map join)適用於join的時候某一張表的數據量比較小的時候,如果兩張表都很大,則不適用這種方式。

如果不能避免shuffle操作也不能過濾傾斜的key值,那麼我們就要從key值的類型入手,如果傾斜的key值是連續的,不是由單個key值引起的,就可以增大task的數量,

比如,修改shuffle產生的partition參數為更大,就可以使同一個范圍內的key值分到不同機器上,

或者使key值重新排列,倒排或者其他方式,使他們不再連續,分配到不同的機器上,就可以防止傾斜。

上述3個操作都比較簡單高效,但是應用的場景有限,如果該key不能被過濾,也不能避免shuffle,而且是1個到多個不連續的key引起的,就需要做比較復雜的操作了。配孝攜

如果是group by,就可以用兩階段聚合法,

將group by a 改成 group by a,b  ,然後再group by a

或者增加一個隨機數x,將a通過concat(x,a)改成b,將group by a 改成 group by b, 然後再聚合一次去掉x後的b,group by substr(b,length(x)) 

如果是join操作,就需要分開join,將傾斜的數據和不傾斜的數據分成兩部分。

然後兩站表不傾斜的部分join得到第一張表。

傾斜的數據,第一張較大的表:增加一個隨機數1-x,隨機數取決於你想把數據切成幾份。

得到 concat(x,a). 

另一張較小的表將每一行復制到x份(總共增加x-1份),然後按順序標上序號1到x,如下所示:

源數據,傾斜的key值為a和b,

大表:aaaaa bbbbb 

小表:aaaa bbbb

原來的join最後得到40條數據. 每個key分到20條

處理過key的表,

大表:1a 2a 2a 1a 2a 1b 2b 3b 3b 2b  (增加一個隨機數前綴1-3)

小表:

1a 2a 3a 1a 2a 3a 1a 2a 3a 1a 2a 3a 這n條數據都按順序附加一個1~x的前綴

1b 2b 3b 1b 2b 3b 1b 2b 3b 1b 2b 3b

生成40條數據,每個key平均分到6.66條.

6.66條的計算公式是5/3*4,  5是大表的key的條數,有5個,增加隨機數之後,被分成了3份,得到了5/3 條,小表雖然也加了隨機數但是復制了x份,

所以小表的key還是4個,所以是:5/3*4

最後將傾斜部分的數據和不傾斜的部分的數據分別join之後再union起來就可以了。

當然,解決數據傾斜的不止這些方法,這些方法只是常用的,本質還是打散集中在某台機器,某個task的的數據量。只要能達到這個目的,就可以。

❸ HIVE優化場景七--數據傾斜--group by 傾斜

HIVE優化場景七--數據傾斜:

GROUP BY 場景下的數據傾斜

JOIN 場景下的數據傾斜

1) 由於空值導致的數據傾斜問題

2) 由於數據類型不一致,導致的轉換問題,導致的數據睜族緩傾斜

3) 業務數據本身分布不均,導致的數據傾斜,下面4個小場景

i.大表與小表JOIN (Map JOIN)

ii.大表與大表JOIN, 一張表數據分布均勻,另一張表數據特定的KEY(有限幾個) 分布不均

iii.大表與大表JOIN, 一張表數據分布均勻,另一張表大量的KEY 分布不均

iiii.大表與大表JOIN, 桶表,進行表拆分

group by 場景下的其實比較簡單,我們只需要在 HIVE 中設置如下兩個參數即可 :

set hive.map.aggr=true;

set hive.groupby.skewindata=true;

我們看下,設置這兩個參數為什麼能解決 GROUP BY 的數據傾斜問題

set hive.map.aggr=true; (默認 : true)   第一個參數表示在 Map 端進行預聚。 因為傳到數據量小了,所以效率高了,可以緩解數據傾斜問題。

最主要的參數,其實是 set hive.groupby.skewindata=true;  

這個參數有什麼作穗渣用呢。這場來說 GROUP BY 流程只會產生一個MR JOB。但是,設置這個參數為 true 以後, 原來 GROUP BY 的 MR JOB 會由原來的一個變為兩個。

流程如下:

JOB1 .第一個作業會進行預處理,將數據進行預聚合,並隨機分發到 不同的 Recer 中。

      Map流程悉模 : 會生成兩個job來執行group by,第一個job中,各個map是平均讀取分片的,在map階段對這個分片中的數據根據group by 的key進行局部聚合操作,這里就相當於Combiner操作。

     Shuffle流程:在第一次的job中,map輸出的結果隨機分區,這樣就可以平均分到rece中  

     Rece流程:  在第一次的job中,rece中按照group by的key進行分組後聚合,這樣就在各個rece中又進行了一次局部的聚合。

JOB2.讀取上一個階段MR的輸出作為Map輸入,並局部聚合。按照key分區,將數據分發到 Rece 中,進行統計。

      Map流程 : 因為第一個job中分區是隨機的,所有rece結果的數據的key也是隨機的,所以第二個job的map讀取的數據也是隨機的key,所以第二個map中不存在數據傾斜的問題。

在第二個job的map中,也會進行一次局部聚合。

    Shuffle流程 :  第二個job中分區是按照group by的key分區的,這個地方就保證了整體的group by沒有問題,相同的key分到了同一個rece中。

    Rece流程 :經過前面幾個聚合的局部聚合,這個時候的數據量已經大大減少了,在最後一個rece里進行最後的整體聚合。

SQL:

SELECT 

 pt,COUNT(1)

FROM datacube_salary_org

GROUP BY pt

;

開啟前

STAGE DEPENDENCIES:                               

  Stage-1 is a root stage                         

  Stage-0 depends on stages: Stage-1             

STAGE PLANS:                                     

  Stage: Stage-1                                 

    Map Rece                                   

      Map Operator Tree:                         

          TableScan                               

            alias: datacube_salary_org           

            Statistics: Num rows: 7 Data size: 1628 Basic stats: COMPLETE Column stats: COMPLETE

            Select Operator                       

              expressions: pt (type: string)     

              outputColumnNames: pt               

              Statistics: Num rows: 7 Data size: 1628 Basic stats: COMPLETE Column stats: COMPLETE

              Group By Operator                   

                aggregations: count(1)           

                keys: pt (type: string)           

                mode: hash                       

                outputColumnNames: _col0, _col1   

                Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE

                Rece Output Operator           

                  key expressions: _col0 (type: string)

                  sort order: +                   

                  Map-rece partition columns: _col0 (type: string)

                  Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE

                  value expressions: _col1 (type: bigint)

      Rece Operator Tree:                       

        Group By Operator                         

          aggregations: count(VALUE._col0)       

          keys: KEY._col0 (type: string)         

          mode: mergepartial                     

          outputColumnNames: _col0, _col1         

          Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE

          File Output Operator                   

            compressed: false                     

            Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE

            table:                               

                input format: org.apache.hadoop.mapred.SequenceFileInputFormat

                output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat

                serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe

  Stage: Stage-0                                 

    Fetch Operator                               

      limit: -1                                   

      Processor Tree:                             

        ListSink                                 

開啟後:

STAGE DEPENDENCIES:                               

  Stage-1 is a root stage                         

  Stage-2 depends on stages: Stage-1             

  Stage-0 depends on stages: Stage-2             

STAGE PLANS:                                     

  Stage: Stage-1                                 

    Map Rece                                   

      Map Operator Tree:                         

          TableScan                               

            alias: datacube_salary_org           

            Statistics: Num rows: 7 Data size: 1628 Basic stats: COMPLETE Column stats: COMPLETE

            Select Operator                       

              expressions: pt (type: string)     

              outputColumnNames: pt               

              Statistics: Num rows: 7 Data size: 1628 Basic stats: COMPLETE Column stats: COMPLETE

              Group By Operator                   

                aggregations: count(1)           

                keys: pt (type: string)           

                mode: hash                       

                outputColumnNames: _col0, _col1   

                Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE

                Rece Output Operator           

                  key expressions: _col0 (type: string)

                  sort order: +                   

                  Map-rece partition columns: rand() (type: double)

                  Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE

                  value expressions: _col1 (type: bigint)

      Rece Operator Tree:                       

        Group By Operator                         

          aggregations: count(VALUE._col0)       

          keys: KEY._col0 (type: string)         

          mode: partials                         

          outputColumnNames: _col0, _col1         

          Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE

          File Output Operator                   

            compressed: false                     

            table:                               

                input format: org.apache.hadoop.mapred.SequenceFileInputFormat

                output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat

                serde: org.apache.hadoop.hive.serde2.lazybinary.LazyBinarySerDe

  Stage: Stage-2                                 

    Map Rece                                   

      Map Operator Tree:                         

          TableScan                               

            Rece Output Operator               

              key expressions: _col0 (type: string)

              sort order: +                       

              Map-rece partition columns: _col0 (type: string)

              Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE

              value expressions: _col1 (type: bigint)

      Rece Operator Tree:                       

        Group By Operator                         

          aggregations: count(VALUE._col0)       

          keys: KEY._col0 (type: string)         

          mode: final                             

          outputColumnNames: _col0, _col1         

          Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE

          File Output Operator                   

            compressed: false                     

            Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE

            table:                               

                input format: org.apache.hadoop.mapred.SequenceFileInputFormat

                output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat

                serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe

  Stage: Stage-0                                 

    Fetch Operator                               

      limit: -1                                   

      Processor Tree:                             

        ListSink                                 

可以明顯的看到開啟優化後。增加了一層 JOB 

❹ 數據傾斜(一):數據傾斜及具體場景

相信大部分做數據的童鞋們都會遇到數據傾斜,數賣首據傾斜會發生在數據開發的各個環節中,比如:

1.用Hive算數據的時候rece階段卡在99.99%

2.用SparkStreaming做實時演算法時候,一直會有executor出現OOM的錯誤,但是其餘的executor內存使用率卻很低。

3.這些問題經常會困擾我們,辛辛苦苦等了幾個小時的數據就是跑不出來,心裡多難過啊。

為什麼要突出這么大數據量?先說一下筆者自己最初對數據量的理解:

數據量大就了不起了?數據量少,機器也少,計算能力也是有限的,因此難度也是一樣的。憑什麼數據量大就會有數據傾斜,數據量小就沒有?

這樣理解也有道理,但是比較片面,舉兩個場景來對比:

公司一:總用戶量1000萬,5台64G內存的的伺服器。
公司二:總用戶量10億,1000台64G內存的伺服器。

兩個公司都部署了Hadoop集群。假設現在遇到了數據傾斜,發生什麼?

1.公司一的數據分析師在做join的時候發生了數據傾斜,會導致有幾百萬用戶的相關數據集中到了一台伺服器上,幾百萬的用戶數據,說大也不大,正常欄位量的數據的話64G還是能輕松處理掉的。
2.公司二的數據分析師在做join的時候也發生了數據傾斜,可能會有1個億的用戶相關數據集中到了一台機器上了(相信我,這很常坦核見)。這時候一台機器就很難搞定了,最後會很難算出結果。

下面會分幾個場景來描述一下數據傾斜的特徵,方便讀者辨別。由於Hadoop和Spark是最常見的兩個計算平台,下面就以這兩個平台說明。

Hadoop中直接貼近用戶使用使用的時Maprece程序和Hive程序,雖說Hive最後也是用MR來執行(至少目前Hive內存計算並不普及),但是畢竟寫的內容邏輯區別很大,一個是程序,一個是Sql,因此這里稍作區分。

具體表現:

Hadoop中的數據傾斜主要表現在: Rece階段卡在99.99%,一直不能結束。

這里如果詳細的看日誌或者和監控界面的話會發現:

Spark中的數據傾斜也讓配掘很常見,這里包括Spark Streaming和Spark Sql,表現主要有下面幾種:

❺ hive數據傾斜及處理

火山日常啰嗦
學習了一些大數據的相關框架後,發現應用層的東西確實不難,真正難的都是底層原理,所以我查看了很多資料,借鑒了前人的方法再加上自己的理解,寫下了這篇文章。

數據傾斜的直白概念:
數據傾斜就是數據的分布不平衡,某些地方特別多,某些地方又特別少,導致的在處理數據的時候,有些很快就處理完了,而有些又遲遲未能處理完,導致整體任務最終遲遲無法完成,這種現象就是數據傾斜。

針對maprece的過程來說就是,有多個rece,其中有一個或者若干個rece要處理的數據量特別大,而其他的rece處理的數據量則比較小,那麼這些數據量小的rece很快就可以完成,而數據量大的則需要很多時間,導致整個任務一直在等它而遲遲無法完成。
跑mr任務時常見行散巧的rece的進度總是卡在99%,這種現象很大可能就是數據傾斜造成的。

產生數據傾斜的原因:
1) key的分布不均勻或者說某些key太集中。
上面就說過,rece的數據量大小差異過大,而rece的數據是分區的結掘尺果,分區是對key求hash值,根據hash值決定該key被分到某個分區,進而進入到某個rece,而如果key很集中或者相同,那麼計算得到它們的hash值可能一樣,那麼就會被分配到同一個rece,就會造成這個rece所要處理的數據量過大。
2) 業務數據自身的特性。
比如某些業務數據作為key的欄位本就很集中,那麼結果肯定會導致數據傾斜啊。
還有其他的一些原因,但是,根本原因還是key的分布不均勻,而其他的原因就是會造成key不均勻,進而導致數據傾斜的後果,所以說根本原因是key的分布不均勻。

既然有數據傾斜這種現象,就必須要有數據傾斜對應的處理方案啊。
簡單地說數據傾斜這種現象導致的任務遲遲不能完成,耗費了太多時間,極大地影響了性能,所以我們數據傾斜的解決方案檔鍵設計思路就是往如何提高性能,即如何縮短任務的處理時間這方面考慮的,而要提高性能,就要讓key分布相對均衡,所以我們的終極目標就是考慮如何預處理數據才能夠使得它的key分布均勻。

常見的數據傾斜處理方案:
1 設置參數
1)設置hive.map.aggr=true //開啟map端部分聚合功能,就是將key相同的歸到一起,減少數據量,這樣就可以相對地減少進入rece的數據量,在一定程度上可以提高性能,當然,如果數據的減少量微乎其微,那對性能的影響幾乎沒啥變化。
2)設置hive.groupby.skewindata=true //如果發生了數據傾斜就可以通過它來進行負載均衡。當選項設定為 true,生成的查詢計劃會有兩個 MR Job。第一個 MR Job 中,Map 的輸出結果集合會隨機分布到 Rece 中,每個 Rece 做部分聚合操作,並輸出結果,這樣處理的結果是相同的Key 有可能被分發到不同的 Rece 中,從而達到負載均衡的目的;第二個 MR Job 再根據預處理的數據結果按照Key 分布到 Rece 中(這個過程是按照key的hash值進行分區的,不同於mr job1的隨機分配,這次可以保證相同的Key 被分布到同一個 Rece 中),最後完成最終的聚合操作。所以它主要就是先通過第一個mr job將key隨機分配到rece,使得會造成數據傾斜的key可能被分配到不同的rece上,從而達到負載均衡的目的。到第二個mr job中,因為第一個mr job已經在rece中對這些數據進行了部分聚合(就像單詞統計的例子,a這個字母在不同的rece中,已經算出它在每個rece中的個數,但是最終的總的個數還沒算出來,那麼就將它傳到第二個mr job,這樣就可以得到總的單詞個數),所以這里直接進行最後的聚合就可以了。
3)hive.exec.recers.bytes.per.recer=1000000000 (單位是位元組)
每個rece能夠處理的數據量大小,默認是1G
4)hive.exec.recers.max=999
最大可以開啟的rece個數,默認是999個
在只配了hive.exec.recers.bytes.per.recer以及hive.exec.recers.max的情況下,實際的rece個數會根據實際的數據總量/每個rece處理的數據量來決定。
5)mapred.rece.tasks=-1
實際運行的rece個數,默認是-1,可以認為指定,但是如果認為在此指定了,那麼就不會通過實際的總數據量/hive.exec.recers.bytes.per.recer來決定rece的個數了。

2 sql語句優化
給幾個具體的場景以及在這些場景下的處理方案:
1)進行表的join這種業務操作時,經常會產生數據傾斜。
原因就是這些業務數據本就存在key會分布不均勻的風險,所以我們join時不能使用普通的join(rece端join)或者可以使用普通join,但是是優化後的。

但是這種操作有個前提條件就是僅適用於小表join大表,而小表怎麼定義它的大小,多小的表才算小表,這里有個參數可以確定的(但是這個參數名我暫時忘記了),如果小表的數據大小小於這個值,就可以使用map join,而是在這種情況下是自動使用map join這種方案的。所以如果是大小表join,直接用map join,避免數據傾斜。

方法1:(普通join)
select * from log a join users b on (a.user_id is not null and a.user_id = b.user_id );
這是屬於表的內連接的,兩張表不滿足條件的記錄都不保留。

方法2:檢測到user_id是null時給它賦予一個新值(這個新值由一個字元串(比如我自己給它定一個 hive)加上一個隨機數組成),這樣就可以將原來集中的key分散開來,也避免了數據傾斜的風險。而且因為這些數據本來就是無效數據,根本不會出現在結果表中,所以,這樣處理user_id(由一個字元串(比如我自己給它定一個 hive)加上一個隨機數),它也無法關聯的,因為有效的數據的user_id沒有這種形式的,所以就算這些無效數據出現在不同的rece中還是不會影響結果的,我這樣處理只是為了將它們分散開而已,所以用這種方法處理,結果表中也不會出現null這些無效數據,跟過濾處理方案得到的結果是一樣的。(普通join)
select *
from log a
join users b
on case when a.user_id is null then concat(『hive』,rand() ) else a.user_id end = b.user_id;
但是這兩種方案只是適用於大表join大表的內連接,兩張表的無效數據都不保留。
但是如果對於左外連接或者右外連接這種情況,即使驅動表中某些記錄在另一張表中沒有數據與它對應,但我們是依然需要保留驅動表的這些數據的,那該怎麼辦呢?其實很簡單,只需要將上述方法得到的結果再與驅動表的這些無數據取並集就可以了。
如下:
select * from log a
left outer join users b
on a.user_id is not null
and a.user_id = b.user_id
union all
select * from log a
where a.user_id is null;
2)雖然都是大表,但是呢對於某些業務數據而言,其有用的部分只佔它所在表的很少一部分,那麼我們就可以將它們先取出來,得到的結果應該是一張小表,那麼就可以使用map join來避免數據傾斜了。

場景:用戶表中user_id欄位為int,log表中user_id欄位既有string類型也有int類型。
當按照user_id進行兩個表的Join操作時,因為我們在連接時要進行user_id的比較,所以需要user_id的類型都相同,如果我們選擇將log表中的String類型轉換為int類型,那麼就可能會出現這種情況:String類型轉換為int類型得到的都是null值(這就是類型轉換的問題了,String類型數據轉換為int類型會失敗,數據丟失,就會賦null值),如果所有的String類型的user_id都變成了null,那麼就又出現了集中的key,分區後就又會導致數據傾斜。所以我們進行類型轉換時不能選擇將String類型轉換為int,而應該將int類型轉換為String,因為int轉換為String不會出問題,int類型原來的值是什麼,轉換為String後對應的字元串就會是什麼,形式沒變,只是類型變了而已。
解決方法:把int類型轉換成字元串類型
select * from users a
join logs b
on (a.usr_id = cast(b.user_id as string));

比如有一份日誌,要你從日誌中統計某天有多少個用戶訪問網站,即統計有多少個不同的user_id;但是呢這個網站卻又恰巧遭到攻擊,日誌中大部分都是同一個user_id的記錄,其他的user_id屬於正常訪問,訪問量不會很大,在這種情況下,當你直接使用count(distinct user_id)時,這也是要跑mr任務的啊,這時這些大量的相同的user_id就是集中的key了,結果就是通過分區它們都被分到一個rece中,就會造成這個rece處理的數據特別大,而其中的rece處理的數據都很小,所以就會造成數據傾斜。
那麼要怎麼優化呢?
方法1:可以先找出這個user_id是什麼,過濾掉它,然後通過count(distinct user_id)計算出剩餘的那些user_id的個數,最後再加1(這1個就是那個被過濾掉的user_id,雖然它有大量的記錄,但是ser_id相同的都是同一個用戶,而我們要計算的就是用戶數)
sql語句展示:
分組求和後降序排序,就可以得到這個數據量最大的user_id是什麼,然後我們下一步操作時就過濾它,等計算完其他的再加上它這一個。
select user_id,count(user_id) from log group by user_id desc limit 2;
select count(distinct user_id)+1 as sum from log;
sum就是最終的結果--用戶數
方法2:我們可以先通過group by分組,然後再在分組得到的結果的基礎之上進行count
sql語句展示:
select count(*) from (select user_id from log group by user_id) new_log;

總的來說就是,數據傾斜的根源是key分布不均勻,所以應對方案要麼是從源頭解決(不讓數據分區,直接在map端搞定),要麼就是在分區時將這些集中卻無效的key過濾(清洗)掉,或者是想辦法將這些key打亂,讓它們進入到不同的rece中。

性能調優是指通過調整使得機器處理任務的速度更快,所花的時間更少,而數據傾斜的處理是hive性能調優的一部分,通過處理能夠大大減少任務的運行時間。

除了數據傾斜的處理之外,hive的優化還有其他方面的,例如where子句優化:
select * from a left outer join b on (a.key=b.key) where a.date='2017-07-11' and b.date='2017-07-11';
這是一個左外連接。
這個sql語句執行的結果是:得到的結果是表a與表b的連接表,且表中的記錄的date都是'2017-07-11'。
而這個sql語句的執行過程是:逐條獲取到a表的記錄,然後掃描b表,尋找欄位key值為a.key的記錄,找到後將b表的這條記錄連接到a表上,然後判斷連接後的這條記錄是否滿足條件a.date='2017-07-11' and b.date='2017-07-11',如果滿足,則顯示,否則,丟棄。
因為這是一個左外連接,且a為驅動表,連接時在a中發現key而在b中沒有發現與之相等的key時,b中的列將置為null,包括列date,一個不為null,一個為null,這樣後邊的where就沒有用了。
簡答的說這個方案的做法就是先按連接條件進行連接,連接後再看where條件,如果不滿足就丟棄,那之前連接所做的那些功夫就浪費了,白白耗費了資源(cpu等),增加了運行的總時間,如果有一種方案可以在未進行連接之前就直接判斷出不滿足最終的條件,那麼就可以直接丟棄它,這樣對於這樣的記錄就不要浪費資源以及時間去連接了,這樣也是能提升性能的,下面就看看這種方案:
sql語句:
將剛才的where限制條件直接放到on裡面,那麼就變成了滿足這三個條件才會進行連接,不滿足的直接過濾掉,就像上面所說的,少了無效連接那一步,就相對地節約了時間,如果這樣的無效連接的記錄很多的話,那麼採用這種改進版的方案無疑能夠較大程度地提高性能。
select * from a left outer join b on (a.key=b.key and a.date='2017-07-11' and b.date='2017-07-11');

不管怎麼說,我們在運行任務時,總是希望能加快運行速度,縮短運行時間,更快地得到結果,即提升性能,這是我們的目的,這就是我們所謂的性能調優。

關於小表join大表的補充:
表join時的操作是這樣的:
當操作到驅動表的某條記錄時,就會全局掃描另一張表,尋找滿足條件的記錄,而當掃描它時,為了讀取速度更快,一般都選先將它載入到內存,而內存的大小是有限的,為了不佔據過多的內存或者避免內存溢出,載入進入內存的表一般是小表,即數據量比較小,map join就是這樣做的。
即驅動表不放進內存,而另一張表(即要連接到驅動表的那一張表)就要先載入進內存,為了掃描速度更快,提高性能。
比如select * from a left outer join b on (a.key=b.key);
左外連接,驅動表是a,表b的記錄是要被連接到表a的,所以每在a上連接一條記錄就要被全局掃描一次的表是b,所以表b應先載入到內存(前提是表b是小表,如果是大表的話,估計會產生oom異常--out of memory內存溢出異常)。

select * from aa right outer join bb on (a.key=b.key);
右外連接,驅動表是bb,aa應先載入到內存(前提是小表)。

ps:希望我的分享能幫助到有需要的夥伴哦。我不是大神的哦,如果文中有誤,還請大家不吝賜教,幫忙指正,謝謝了!!!

❻ 幾種數據傾斜的情況,並解釋為什麼會傾斜,以及如何解決

  1. Mapjoin是一種避免避免數據傾斜的手段

允許在map階段進行join操作,MapJoin把小表全部讀入內存中,在map階段直接拿另外一個表的數據和內存中表數據做匹配,由於在map是進行了join操作,省去了rece運行的效率也會高很多


在《hive:join遇到問題》有具體操作


在對多個表join連接操作時,將小表放在join的左邊,大表放在Jion的右邊,


在執行中仿敬這樣的join連接時小表中的數據會被緩存到內存當中,這樣可以有效減少發生內存溢出錯誤的幾率


2. 設置參數


hive.map.aggr = true


hive.groupby.skewindata=true 還有其他參數


3.SQL語言調節


比如: group by維度過小時:采大滑用sum() group by的方式來替換count(distinct)完成計算


4.StreamTable


將在recer中進行join操作時的小賣慎table放入內存,而大table通過stream方式讀取

❼ 數據倉庫面試題

一般數據倉庫面試會面兩輪,第一輪一般是sql技術面,第二輪就是 維度建模 和 數據治理 的問題。

一輪技術面(待補充):

1、數據傾斜:

數據傾斜一般產生的原因是數據在map端hash分配到rece端時,某一個key的數量遠大於其他的key,導致某一個rece的處理時間較長。

1)key分布不均勻
2)數據本身就是如此
3)數據關聯時沒有把握好關聯鍵

解決方案

1)參數調整:hive.map.aggr = true;hive.groupby.skewindata=true;
 當存在數據傾斜時開啟負載均衡,此時會生成兩個MapRece任務,第一個MR任務會將map端產生的key隨機的分配到rece,先進行一次聚合,第二個MR任務會將第一個任務的預處理結果作為輸入,將相同的key分配到同一個rece當中。
2)sql調整:在處理大量空值導致數據傾斜的情況下,可以先將空值附一個特殊值去處理,比如給一個隨機數加字元串的方式,因為空值數據是關聯不上的,不會影響後期處理。

2、order by,sort by,cluster by,distribute by的區別

1)order by是全局排序,排序過程在一個rece中進行,在數據量較大時就會很慢
2)sort by是局部排序,排序結果在同一個rece中使有序的
3)distribute by是將數據按照欄位劃分到一個rece中,一般與sort by連用進行分組排序的作用
4)cluster by除具有distribute by功能外慎首滑還具有sort by的功能

order by優化(阿裡面試):
1)開啟嚴格模式,order by之後添加limit子句
2)利用sort by,在每個rece中先排序取出top項,再把預處理結果order by輸出

3、hive中內部表和外部表的區別

1)在創建表的時候,內部表是將數據移動到數據倉庫指向的路徑,外部表僅記錄數據所在的路徑,不對數據的位置做任何改變。
2)在刪除表的時候,內部表會將元數據和數據都刪除,外部表只刪除元芹升數據。

4、列轉行、行轉列

1)列轉行:lateral view explode(split('column_name',','))作為寬臘一個新表
2)行轉列:concat_ws(',',collect_set(column_name))

5、maprece運行原理

6、數據倉庫分層原理(阿裡面試)

7、維度建模中三種事實表的應用場景(阿裡面試)

二輪面試(待補充)