- Hive調(diào)優(yōu)作用:在保證業(yè)務(wù)結(jié)果不變的前提下,降低資源的使用量,減少任務(wù)的執(zhí)行時間。
1、調(diào)優(yōu)須知
(1)對于大數(shù)據(jù)計算引擎來說:數(shù)據(jù)量大不是問題,數(shù)據(jù)傾斜是個問題。
(2)Hive的復(fù)雜HQL底層會轉(zhuǎn)換成多個MapReduce Job并行或者串行執(zhí)行,Job數(shù)比較多的作業(yè)運行效 率相對比較低,比如即使只有幾百行數(shù)據(jù)的表,如果多次關(guān)聯(lián)多次匯總,產(chǎn)生十幾個Job,耗時很長。 原因是 MapReduce 作業(yè)初始化的時間是比較長的。
(3)在進行Hive大數(shù)據(jù)分析時,常見的聚合操作比如sum,count,max,min,UDAF等 ,不怕數(shù)據(jù)傾斜問題**,MapReduce 在 Mappe階段 的預(yù)聚合操作,使數(shù)據(jù)傾斜不成問題**。 (4)好的建表設(shè)計,模型設(shè)計事半功倍。
(5)設(shè)置合理的 MapReduce 的 Task 并行度,能有效提升性能。(比如,10w+數(shù)據(jù)量 級別的計算,用 100 個 reduceTask,那是相當?shù)睦速M,1個足夠,但是如果是 億級別的數(shù)據(jù)量,那么1個Task又顯得捉 襟見肘)
(6)了解數(shù)據(jù)分布,自己動手解決數(shù)據(jù)傾斜問題是個不錯的選擇。這是通用的算法優(yōu)化,但算法優(yōu)化有 時不能適應(yīng)特定業(yè)務(wù)背景,開發(fā)人員了解業(yè)務(wù),了解數(shù)據(jù),可以通過業(yè)務(wù)邏輯精確有效的解決數(shù)據(jù)傾斜 問題。
(7)對小文件進行合并,是行之有效的提高調(diào)度效率的方法,假如所有的作業(yè)設(shè)置合理的文件數(shù),對任務(wù)的整體調(diào)度效率也會產(chǎn)生積極的正向影響
(8)優(yōu)化時把握整體,單個作業(yè)最優(yōu)不如整體最優(yōu)。
2、Hive的建表設(shè)計層面
2.1、建表類型 - 分區(qū)VS分桶
(1)分區(qū)表
? 當一個 Hive 表的查詢大多數(shù)情況下,會根據(jù)某一個字段進行篩選時,那么非常適合創(chuàng)建為 分區(qū)表,該字段即為分區(qū)字段。
- 應(yīng)用場景:數(shù)據(jù)基本上只會分析增量數(shù)據(jù),不會分析全量數(shù)據(jù),則應(yīng)該按照時間來分區(qū)
(2)分桶表
? 指將數(shù)據(jù)以指定列的值為 key 進行 hash,hash 到指定數(shù)目的桶中,這樣做的 目的和分區(qū)表類似,使得篩選時不用全局遍歷所有的數(shù)據(jù),只需要遍歷所在桶就可以了
- 應(yīng)用場景:AB試驗數(shù)據(jù)采樣、Join數(shù)據(jù)傾斜
2.2、選擇合適的文件存儲格式
- 優(yōu)化方案:、表的文件存儲格式盡量采用Parquet或ORC,不僅降低存儲量,還優(yōu)化了查詢,壓縮,表關(guān)聯(lián)等性能
(1)TextFile : 每一行都是一條記錄,每行都以換行符(\ n)結(jié)尾。數(shù)據(jù)不做壓縮,磁盤開銷大,數(shù)據(jù)解析開銷大。可結(jié)合Gzip、Bzip2使用(系統(tǒng)自動檢查,執(zhí)行查詢時自動解壓),但使用這種方式,hive不會對數(shù)據(jù)進行切分,從而無法對數(shù)據(jù)進行并行操作。
(2)SequenceFile : 是Hadoop API提供的一種二進制文件支持,其具有使用方便、可分割、可壓縮的特點。支持三種壓縮選擇:NONE, RECORD, BLOCK。 Record壓縮率低,一般建議使用BLOCK壓縮。
(3)RCFile : 是一種行列存儲相結(jié)合的存儲方式。首先,其將數(shù)據(jù)按行分塊,保證同一個record在一個塊上,避免讀一個記錄需要讀取多個block。其次,塊數(shù)據(jù)列式存儲,有利于數(shù)據(jù)壓縮和快速的列存取。
ORCFile : ORC文件格式提供了一種將數(shù)據(jù)存儲在Hive表中的高效方法。這個文件系統(tǒng)實際(4)上是為了克服其他Hive文件格式的限制而設(shè)計的。Hive從大型表讀取,寫入和處理數(shù)據(jù)時,使用ORC文件可以提高性能。
(5)Parquet : 一個面向列的二進制文件格式。Parquet對于大型查詢的類型是高效的。對于掃描特定表格中的特定列的查詢,Parquet特別有用。
存儲格式 | 存儲方式 | 特點 |
---|---|---|
TextFile | 行存儲 | 存儲空間消耗比較大,并且壓縮的text 無法分割和合并 查詢的效率最低,可以直接存儲,加載數(shù)據(jù)的速度最高 |
SequenceFile | 行存儲 | 存儲空間消耗最大,壓縮的文件可以分割和合 ,查詢效率高,需要通過text文件轉(zhuǎn)化來加載,適合全量表的讀取 |
RCFile | 數(shù)據(jù)按行分塊 每塊按照列存儲 | 存儲空間最小,查詢的效率最高 ,需要通過text文件轉(zhuǎn)化來加載,加載的速度最低。壓縮快 快速列存取。讀記錄盡量涉及到的block最少,讀取需要的列只需要讀取每個row group 的頭部定義。 讀取全量數(shù)據(jù)的操作 性能可能比sequencefile沒有明顯的優(yōu)勢 |
ORCFile | 數(shù)據(jù)按行分塊 每塊按照列存儲 | ORC File會基于列創(chuàng)建索引,當查詢的時候會很快 |
Parquet | 列存儲 | 相對于ORC,Parquet壓縮比較低,查詢效率較低,不支持update、insert和ACID.但是Parquet支持Impala查詢引擎 |
2.3、選擇合適的文件壓縮格式
- 含義:Hive 語句最終是轉(zhuǎn)化為 MapReduce 程序來執(zhí)行的,而 MapReduce 的性能瓶頸在與 網(wǎng)絡(luò)IO 和 磁盤 IO,要解決性能瓶頸,最主要的是減少數(shù)據(jù)量,對數(shù)據(jù)進行壓縮是個好方式。
(1)壓縮比:壓縮比越高,壓縮后文件越小,所以壓縮比越高越好
(2)壓縮時間:越快越好
(3)已經(jīng)壓縮的格式文件是否可以再分割:可以分割的格式允許單一文件由多個Mapper程序處理,可以更好的并行化
- 是否壓縮的前提
1、計算密集型,不壓縮,否則進一步增加了CPU的負擔
2、網(wǎng)絡(luò)密集型,推薦壓縮,減小網(wǎng)絡(luò)數(shù)據(jù)傳輸
3、HiveSQL語句優(yōu)化
3.1、列裁剪
- 含義: Hive 在讀數(shù)據(jù)的時候,可以只讀取查詢中所需要用到的列,而忽略其它列。【裁剪所對應(yīng)的參數(shù)項為:hive.optimize.cp=true(默認值為真)】
set hive.optimize.cp = true; ## 列裁剪,取數(shù)只取查詢中需要用到的列,默認是true
- 主要作用:節(jié)省了讀取開銷,中間表存儲開銷和數(shù)據(jù)整合開銷?!緶p少磁盤讀寫開銷、網(wǎng)絡(luò)IO開銷】
3.2、謂詞下推
- 含義:將 SQL 語句中的 where 謂詞邏輯都盡可能提前執(zhí)行,減少下游處理的數(shù)據(jù)量。對應(yīng)邏輯優(yōu)化器是 PredicatePushDown。
set hive.optimize.ppd=true; ## 默認是true
select a.*, b.* from a join b on a.id = b.id where b.age > 20;
#優(yōu)化后
select a.*, c.* from a join (select * from b where age > 20) c on a.id = c.id
3.3、分區(qū)裁剪
- 含義: 可以在查詢的過程中減少不必要的分區(qū)。【分區(qū)參數(shù)為:hive.optimize.pruner=true(默認值為真)】
set hive.optimize.pruner=true; ## 默認是true
- 主要作用:減少讀取開銷以及中間表存儲開銷和數(shù)據(jù)整合開銷,減少磁盤IO與網(wǎng)絡(luò)IO
3.4、合并小文件
- 含義:合理設(shè)置map數(shù)量,map數(shù)又和文件塊數(shù)量有關(guān),一個文件塊對應(yīng)一個map,小文件過多勢必造成啟動map任務(wù)和初始劃的時間遠遠大于邏輯處理時間,所以在map執(zhí)行前合并小文件,減少map數(shù)
# 1、在 map only 的任務(wù)結(jié)束時合并小文件
set hive.merge.mapfiles = true
# 2、true 時在 MapReduce 的任務(wù)結(jié)束時合并小文件
set hive.merge.mapredfiles = false
# 3、合并文件的大小
set hive.merge.size.per.task = 256*1000*1000
# 4、每個 Map 最大分割大小
set mapred.max.split.size=256000000;
# 5、一個節(jié)點上 split 的最少值
set mapred.min.split.size.per.node=1;
# 6、執(zhí)行Map前進行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
- 注意事項:
- ①默認情況先把這個節(jié)點上的所有數(shù)據(jù)進行合并,如果合并的那個文件的大小超過了256M就開啟另外一個文 件繼續(xù)合并
- ②如果當前這個節(jié)點上的數(shù)據(jù)不足256M,那么就都合并成一個邏輯切片。
3.5、合理設(shè)置MapTask并行度
3.6、合理控制ReduceTask并行度
3.7、Join優(yōu)化
3.8、Group By優(yōu)化
- 含義:Map端部分聚合:事實上并不是所有的聚合操作都需要在 Reduce 部分進行,很多聚合操作都可以先在 Map 端進行部分 聚合,然后在 Reduce 端的得出最終結(jié)果。
## 開啟Map端聚合參數(shù)設(shè)置
set hive.map.aggr=true;
# 設(shè)置map端預(yù)聚合的行數(shù)閾值,超過該值就會分拆job,默認值100000
set hive.groupby.mapaggr.checkinterval=100000
3.9、Order By優(yōu)化
-
含義:order by 只能是在一個 reduce 進程中進行,所以如果對一個大數(shù)據(jù)集進行 order by ,會導致一個 reduce 進程中處理的數(shù)據(jù)相當大,造成查詢執(zhí)行緩慢。
-
解決方案:分桶后進行區(qū)間排序
? 如果是取排序后的前N條數(shù)據(jù),可以使用distribute by和sort by在各個reduce上進行排序后前N 條,然后再對各個reduce的結(jié)果集合合并后在一個reduce中全局排序,再取前N條,因為參與全局排序的 order by的數(shù)據(jù)量最多是reduce個數(shù) * N,所以執(zhí)行效率會有很大提升。
4、Hive配置參數(shù)(Hive架構(gòu)層面)
4.1、Fetch抓取
Fetch抓取:Hive中對某些情況的查詢可以不必使用MapReduce計算,在全局查找、字段查找、limit查找等都不走mapreduce。
(1)把hive.fetch.task.conversion設(shè)置成none,然后執(zhí)行查詢語句,都會執(zhí)行mapreduce程序。
hive (default)> **set hive.fetch.task.conversion=none;**
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;
(2)把hive.fetch.task.conversion設(shè)置成more,如下查詢方式都不會執(zhí)行mapreduce程序。
hive (default)> **set hive.fetch.task.conversion=more;**
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;
4.2、本地執(zhí)行優(yōu)化
? 對于小數(shù)據(jù)集,可以通過本地模式,在單臺機器上處理所有任務(wù),執(zhí)行時間明顯被縮短。
## 打開hive自動判斷是否啟動本地模式的開關(guān)
set hive.exec.mode.local.auto=true;
## map任務(wù)數(shù)最大值,不啟用本地模式的task最大個數(shù)
set hive.exec.mode.local.auto.input.files.max=4;
## map輸入文件最大大小,不啟動本地模式的最大輸入文件大小
set hive.exec.mode.local.auto.inputbytes.max=134217728;
4.3、JVM重用
? 如果任務(wù)花費時間很短,又要多次啟動 JVM 的情況下,JVM 的啟動時間會變成一個比較大的消耗,這時,可以通過重用 JVM 來解決。
set mapred.job.reuse.jvm.num.tasks=5;
- 注意事項:JVM也是有缺點的,開啟JVM重用會一直占用使用到的 task 的插槽,以便進行重用,直到任務(wù)完成后才 會釋放。
4.4、并行度優(yōu)化
- 含義:**Hive會將一個查詢轉(zhuǎn)化成一個或者多個階段,MapReduce階段、抽樣階段、合并階段、limit階段,默認情況hive一次只會執(zhí)行一個階段。**而這些階段可能并非完全互相依賴的,也就是說有些階段是可以并行執(zhí)行的,這樣可能使得整個job的執(zhí)行時間縮短。
set hive.exec.parallel=true; #打開任務(wù)并行執(zhí)行
set hive.exec.parallel.thread.number=16; #同一個sql允許最大并行度,默認為8。
4.5、推測執(zhí)行
? Hadoop采用了推測執(zhí)行(Speculative Execution)機制,它 根據(jù)一定的法則推測出“拖后腿”的任務(wù),并為這樣的任務(wù)啟動一個備份任務(wù),讓該任務(wù)與原始任務(wù)同時處理同一份數(shù)據(jù),并最終選用最先成功運行完成任務(wù)的計算結(jié)果作為最終結(jié)果。
# 啟動mapper階段的推測執(zhí)行機制
set mapreduce.map.speculative=true;
# 啟動reducer階段的推測執(zhí)行機制
set mapreduce.reduce.speculative=true;
- 注意事項:如果用戶因為輸入數(shù)據(jù)量很大而需要執(zhí)行長時間的 mapTask 或者 reduceTask 的話,那么啟動推測執(zhí)行造成的浪費是非常巨大。
5、Hive數(shù)據(jù)傾斜
5.1、數(shù)據(jù)傾斜定義
? 數(shù)據(jù)分布不均,造成大量數(shù)據(jù)集中到一點,造成數(shù)據(jù)熱點。
5.2、數(shù)據(jù)傾斜的表現(xiàn)
(1)在執(zhí)行任務(wù)的時候,任務(wù)進度長時間維持在99%左右;
(2)查看stage的執(zhí)行情況時,卡在最后1-2個task長時間不動,查看task監(jiān)控頁面,發(fā)現(xiàn)某個或某兩三個task運行的時間遠遠大于其他task的運行時間,這些task處理的數(shù)據(jù)量也遠遠大于其他task。
- 注意事項:關(guān)于Hive On Spark,一個spark任務(wù)的運行時間是由最后一個執(zhí)行成功的task決定的,如果某個task發(fā)生了數(shù)據(jù)傾斜,會拖慢整個spark任務(wù)執(zhí)行效率,即便其他沒有傾斜的task已經(jīng)執(zhí)行完畢,甚至會導致OOM
3、查看數(shù)據(jù)傾斜方法
在yarn界面查看是否產(chǎn)生數(shù)據(jù)傾斜:
上圖是yarn界面task的監(jiān)控頁面,從上圖可以看出大部分task的執(zhí)行時間是25s,處理記錄數(shù)為幾萬到幾十萬不等(處理數(shù)據(jù)量大部分為幾兆到幾十兆),但是有一個task處理時間為1小時處理數(shù)據(jù)量高達72G且還沒執(zhí)行完,此時可以推斷數(shù)據(jù)發(fā)生了傾斜,可以通過group by或者抽樣找出傾斜key。
4、數(shù)據(jù)傾斜條件
數(shù)據(jù)計算時發(fā)生了shuffle,即對數(shù)據(jù)進行了重新分區(qū)。
關(guān)鍵詞 | 情形 | 后果 |
---|---|---|
join | 某個或某幾個key比較集中,或者存在大量null key | 分發(fā)到某一個或者某幾個Reduce上的數(shù)據(jù)遠高于平均值 |
group by | 維度過小,某值的數(shù)量過多 | 某個維度或者某幾個維度且這些維度的數(shù)據(jù)量特別大,集中在一個reduce |
5、數(shù)據(jù)傾斜的解決方案
5.1、特殊情形處理
①同數(shù)據(jù)類型關(guān)聯(lián)產(chǎn)生數(shù)據(jù)傾斜
-
情形:比如用戶表中user_id字段為int,log表中user_id字段string類型。當按照user_id進行兩個表的Join操作時。
-
解決方式:把數(shù)字類型轉(zhuǎn)換成字符串類型
select * from users a
left outer join logs b
on a.usr_id = cast(b.user_id as string)
②null key不參與關(guān)聯(lián)
select
a.*
from(
select
*
from log
where user_id is not null
) a
join
users b on a.user_id = b.user_id
union all
select
*
from log where user_id is null
③數(shù)據(jù)加鹽:賦予null值隨機值
1. select *
2. from log a
3. left outer join users b
4. on case when a.user_id is null then concat('hive',rand() ) else a.user_id end = b.user_id;
- 兩種方式優(yōu)缺點比較
方法2比方法1效率更好,不但io少了,而且作業(yè)數(shù)也少了。
解決方法1中 log讀取兩次,jobs是2。解決方法2 job數(shù)是1 ;
這個優(yōu)化適合無效 id (比如 -99 , ’’, null 等) 產(chǎn)生的傾斜問題。
把空值的 key 變成一個字符串加上隨機數(shù),就能把傾斜的數(shù)據(jù)分到不同的reduce上 ,解決數(shù)據(jù)傾斜問題。
④提高reduce并行度
設(shè)置reduce個數(shù):set mapred.reduce.tasks=15,可以通過改參數(shù)提高reduce端并行度,從而緩解數(shù)據(jù)傾斜的情況。
Ⅰ、未優(yōu)化前,假設(shè)key1、key2、key3、key4的數(shù)據(jù)量都是50w,key5是10w,此時key1和key3shuffle到了一個reduce,key2和key4shuffle到了一個reduce,導致有兩個reduce task需要處理100w數(shù)據(jù),而有一個task只需要處理10w數(shù)據(jù),此時數(shù)據(jù)出現(xiàn)了10倍的傾斜。
Ⅱ、優(yōu)化后,如圖所示,為優(yōu)化前reduce的并行度為3,單個task處理的最大數(shù)據(jù)量為100w,現(xiàn)在將并行度提高到5,單個task處理的最大數(shù)據(jù)量為50w,相比之前緩解了5倍的傾斜程度。此方案適合傾斜的程度不是很嚴重,并有兩個以上的傾斜key到shuffle到了同一個reduce。
5.2、group by導致的數(shù)據(jù)傾斜
(1)開啟負載均衡
- 含義:有數(shù)據(jù)傾斜的時候進行負載均衡(默認是false)
set hive.groupby.skewindata = true
- 當選項設(shè)定為 true,生成的查詢計劃會有兩個MR Job。
①第一個MR Job:Map的輸出結(jié)果會隨機分布到Reduce中,每個Reduce做部分聚合操作,并輸出結(jié)果,這樣處理的結(jié)果是相同的Group By Key有可能被分發(fā)到不同的Reduce中,從而達到負載均衡的目的;
②第二個MR Job:根據(jù)預(yù)處理的數(shù)據(jù)結(jié)果按照Group By Key分布到Reduce中(這個過程可以保證相同的Group By Key被分布到同一個Reduce中),最后完成最終的聚合操作。
(2)group by 雙重聚合
當使用group by進行聚合統(tǒng)計時,如果存在某個或某幾個key發(fā)生了傾斜,會導致某個傾斜key shuffle到一個reduce。
select
split(sp_app_id,'_')[0] sp_app_id
,sum(pv)
from
(
select
sp_app_id||'_'||CAST(CAST(MOD(rand() * 10000,10) AS BIGINT) AS STRING) sp_app_id
,sum(nvl(op_cnt, 1)) pv
from t1
group by sp_app_id||'_'||CAST(CAST(MOD(rand() * 10000,10) AS BIGINT) AS STRING)
) group by split(sp_app_id,'_')[0]
5.3、join導致的數(shù)據(jù)傾斜
(1)reduce join 轉(zhuǎn)換成 map join(此方案適合小表join大表的時候)
select /+ mapjoin(t2)/ column from table
(2)過濾傾斜join單獨進行join(此方案適合大表關(guān)聯(lián)達標)
所以如果把傾斜key過濾出來單獨去join,這個傾斜key就會分散到多個task去進行join操作,最后union all。
select
*
from
(
select
*
from t1
where rowkey <> '123456789'
) a1 join a2 on a1.rowkey = a2.rowkey
union all
select
*
from
(
select
*
from t1
where rowkey = '123456789'
)a1 join a2 on a1.rowkey = a2.rowkey
③md5+分桶處理進行關(guān)聯(lián)(PB級別數(shù)據(jù)關(guān)聯(lián)PB級別數(shù)據(jù),提效100倍+)
- 熱點數(shù)據(jù)處理方式:熱點數(shù)據(jù)直接過濾出來分開Join,md5(key1,Key2)后分桶關(guān)聯(lián)
5.4、企業(yè)實戰(zhàn)案例之日志表和用戶表做連接
- 業(yè)務(wù)場景:事實表和維度表做關(guān)聯(lián),即大表關(guān)聯(lián)小表,但是不能直接使用mapJoin
(1)實際業(yè)務(wù)需求
? users 表有 600w+ (假設(shè)有5G)的記錄,把 users 分發(fā)到所有的 map 上也是個不小的開銷,而且 MapJoin 不支持這么大的小表。如果用普通的 join,又會碰到數(shù)據(jù)傾斜的問題。
(2)解決方案文章來源地址http://www.zghlxwxcb.cn/news/detail-658608.html
- 原理:提前排除user表中的沒用的ID,減少小表的數(shù)據(jù)量 ==》可以分別建立用戶的全量表/天級全量表
①先得到過濾的userid
select distinct user_id from log ==》 a
②再獲取有日志記錄得以用戶的信息
select b.* from a join users b on a.user_id = b.user_id; ==》b
③讓C表與log表做關(guān)聯(lián)
select /*+mapjoin(x)*/ * from log c left outer join d
on a.user_id = x.user_id;
5.5、企業(yè)實戰(zhàn)案例之位圖法求連續(xù)七天的朋友圈用戶
- 業(yè)務(wù)場景:事實表和事實表做關(guān)聯(lián),即大表關(guān)聯(lián)大表
(1)實際業(yè)務(wù)需求
每天都要求 微信朋友圈 過去連續(xù)7天都發(fā)了朋友圈的小伙伴有哪些? 假設(shè)每個用戶每發(fā)一次朋友圈都記錄了一條日志。每一條朋友圈包含的內(nèi)容:
日期,用戶ID,朋友圈內(nèi)容.....
dt, userid, content, .....
如果 微信朋友圈的 日志數(shù)據(jù),按照日期做了分區(qū)。
2020-07-06 file1.log(可能會非常大)
2020-07-05 file2.log
.......
(2)解決方案
- 原理:位圖法BitMaps,即維護一個位數(shù)組
假設(shè)微信有10E用戶,我們每天生成一個長度為10E的二進制數(shù)組,每個位置要么是0,要么是1,如果為1,代
表該用戶當天發(fā)了朋友圈。如果為0,代表沒有發(fā)朋友圈。
然后每天:10E / 8 / 1024 / 1024 = 119M左右
求Join實現(xiàn):兩個數(shù)組做 求且、求或、異或、求反、求新增
5.6、企業(yè)實戰(zhàn)案例之用戶留存
- 業(yè)務(wù)場景:事實表與實時表做關(guān)聯(lián),即大表關(guān)聯(lián)大表
(1)實際業(yè)務(wù)需求
? 一般在運營或者BI報表里面,關(guān)于渠道用戶分析時,用戶留存是個不可缺少的過程,也是業(yè)界多渠道用戶質(zhì)量比較成熟的判斷標準,主要指標,包括計算用戶次日、3日、7日、30天、90天等的留存率。文章來源:http://www.zghlxwxcb.cn/news/detail-658608.html
- 指標說明:用戶留存率 -今天新增了100名用戶,第二天登陸了50名,則次日留存率為50/100=50%,第三天登錄了30名,則第二日留存率為30/100=30%
(2)解決方案
- 原理:建立天級全量用戶表
步驟一:從數(shù)據(jù)庫中提取user_id和login_time, 并計算 first_day, 用于存儲每個用戶ID最早登錄日期(最小日期);
步驟二:用登錄日期-最早登錄日期,得到每個登錄日期距離最早登錄日期的時間間隔,即留存日期;
步驟三:對不同留存日期的user_id進行匯總就是留存人數(shù),除以首日登錄人數(shù),就得到了不同留存時間的留存率。
select
a.dt
,count(distinct a.id) as `日活躍用戶`
,count(distinct b.id) as `次日留存數(shù)`
,count(distinct c.id) as `三日留存數(shù)`
,count(distinct d.id) as `七日留存數(shù)`
,concat(round(count(distinct b.id) / count(distinct a.id) * 100, 2), '%') as `次日留存率`
,concat(round(count(distinct c.id) / count(distinct a.id) * 100, 2), '%') as `三日留存率`
,concat(round(count(distinct d.id) / count(distinct a.id) * 100, 2), '%') as `七日留存率`
-- select *
from yhlc a
LEFT join yhlc b on a.id=b.id and b.dt=a.dt+1
LEFT join yhlc c on a.id=c.id and c.dt=a.dt+3
LEFT join yhlc d on a.id=d.id and d.dt=a.dt+7
group by a.dt;
6、終極大招
- 向老板要錢申請加資源
到了這里,關(guān)于第十六章 Hive生產(chǎn)環(huán)境優(yōu)化&數(shù)據(jù)傾斜解決方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!