Hive-常見調優方式 && 兩個面試sql

Hoult丶吳邪發表於2021-02-23

Hive作為大資料領域常用的資料倉儲元件,在設計和開發階段需要注意效率。影響Hive效率的不僅僅是資料量過大;資料傾斜、資料冗餘、job或I/O過多、MapReduce分配不合理等因素都對Hive的效率有影響。對Hive的調優既包含對HiveQL語句本身的優化,也包含Hive配置項和MR方面的調
整。

從以下三個方面展開:
架構優化
引數優化
SQL優化

1.架構方面

執行引擎方面針對公司內平臺的資源,選擇更合適的更快的引擎,比如MR、TEZ、Spark等,

如果選擇是TEZ引擎,可以在優化器時候開啟向量化的優化器,另外可以選擇成本優化器CBO,配置分別如下:

set hive.vectorized.execution.enabled = true; -
- 預設 false
set hive.vectorized.execution.reduce.enabled = true; -
- 預設 false
SET hive.cbo.enable=true; --從 v0.14.0預設
true
SET hive.compute.query.using.stats=true; -- 預設false
SET hive.stats.fetch.column.stats=true; -- 預設false
SET hive.stats.fetch.partition.stats=true; -- 預設true 

在表的設計上優化,比如選擇分割槽表,分桶表,以及表的儲存格式,為了減少資料傳輸,可以使用壓縮的方式,下面給幾個引數(更多引數可以檢視官網)

-- 中間結果壓縮
SET
hive.intermediate.compression.codec=org.apache.hadoop.io.compress.SnappyCodec ;
-- 輸出結果壓縮
SET hive.exec.compress.output=true;
SET mapreduce.output.fileoutputformat.compress.codec =org.apache.hadoop.io.compress.SnappyCodc

2.引數優化

第二部分是引數優化,其實上面架構部分,有部分也是通過引數來控制的,這一部分的引數控制主要有下面幾個方面

本地模式、嚴格模式、JVM重用、並行執行、推測執行、合併小檔案、Fetch模式

2.1 本地模式

當資料量較小的時候,啟動分散式處理資料會比較慢,啟動時間較長,不如本地模式快,用下面的引數來調整

SET hive.exec.mode.local.auto=true; -- 預設 false 
小
SET hive.exec.mode.local.auto.inputbytes.max=50000000; --輸入檔案的大小小於 hive.exec.mode.local.auto.inputbytes.max 配置的大
SET hive.exec.mode.local.auto.input.files.max=5; -- 預設 4  map任務的數量小於 hive.exec.mode.local.auto.input.files.max 配置的
大小

2.2 嚴格模式

這其實是個開關,滿足下面三個語句時候,就會失敗,如果不開啟就正常執行,開啟後就讓這些語句自動失敗

hive.mapred.mode=nostrict
 -- 查詢分割槽表時不限定分割槽列的語句;
 -- 兩表join產生了笛卡爾積的語句;
 -- 用order by來排序,但沒有指定limit的語句 

2.3 Jvm重用

在mr裡面,是以程式為單位的,一個程式就是一個Jvm,其實像短作業,這些程式能夠重用就會很快,但是它的缺點是會等任務執行完畢後task插槽,這個在資料傾斜時候較為明顯。開啟這個使用下面的引數

SET mapreduce.job.jvm.numtasks=5;

2.4 並行執行

Hive的查詢會轉為stage,這些stage並不是相互依賴的,可以並行執行這些stage,使用下面的引數

SET hive.exec.parallel=true; -- 預設false
SET hive.exec.parallel.thread.number=16; -- 預設8

2.5 推測執行

這個引數的作用是,使用空間資源來換取得到最終結果的時間,比如由於網路,資源不均等原因,某些任務執行特別慢,會啟動備份程式處理同一份資料,並最終選用最先成功的計算結果作為最終結果。

set mapreduce.map.speculative=true
set mapreduce.reduce.speculative=true
set hive.mapred.reduce.tasks.speculative.execution=true

2.6 合併小檔案

在map執行前面,先合併小檔案來減少map數

set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

在任務結束後,合併小檔案

# 在 map-only 任務結束時合併小檔案,預設true
SET hive.merge.mapfiles = true;
# 在 map-reduce 任務結束時合併小檔案,預設false
SET hive.merge.mapredfiles = true;
# 合併檔案的大小,預設256M
SET hive.merge.size.per.task = 268435456;
# 當輸出檔案的平均大小小於該值時,啟動一個獨立的map-reduce任務進行檔案merge
SET hive.merge.smallfiles.avgsize = 16777216;

2.7 Fetch模式

最後一種fetch模式,則是在某些情況下儘量不跑mr,比如查詢幾個欄位,全域性查詢,欄位查,limit查等情況

hive.fetch.task.conversion=more

3.sql優化

這一部分較複雜,可能涉及到資料傾斜問題,至於資料傾斜問題一直是大資料處理的不可比避免的一個問題,處理方式也較多

3.1 sql優化

sql優化是開發人員最容易控制的部分,往往是經驗使之,大約總結一下又下面的方式

列,分割槽拆解,sort by 代替 order by, group by 代替count(distinct) ,group by的預聚合(通過引數來控制),傾斜配置項,map join,單獨過濾空值,適當調整map 和 reduces數,這些在工作中幾乎都會碰到,儘可能去優化他們呢是你要做的

3.2 傾斜均衡配置項

這個配置與 group by 的傾斜均衡配置項異曲同工,通過 hive.optimize.skewjoin來配置,預設false。如果開啟了,在join過程中Hive會將計數超過閾值 hive.skewjoin.key (預設100000)的傾斜key對應的行臨時寫進檔案中,然後再啟動另一個job做map join生成結果。通過 hive.skewjoin.mapjoin.map.tasks 引數還可以控制第二個job的mapper數量,預設1000

3.3 單獨處理傾斜key

如果傾斜的 key 有實際的意義,一般來講傾斜的key都很少,此時可以將它們單獨抽取出來,對應的行單獨存入臨時表中,然後打上一個較小的隨機數字首(比如0~9),最後再進行聚合。不要一個Select語句中,寫太多的Join。一定要了解業務,瞭解資料。(A0-A9)分成多條語句,分步執行;(A0-A4; A5-A9);先執行大表與小表的關聯;

4.兩個SQL

4.1 找出全部奪得3連貫的隊伍

team,year
活塞,1990
公牛,1991
公牛,1992


--
 -- 1 排名
select team, year, 
row_number() over (partition by team order by year) as rank
  from t1;

-- 2 獲取分組id
select team, year, 
row_number() over (partition by team order by year) as rank,
(year -row_number() over (partition by team order by year)) as groupid
  from t1;

-- 3 分組求解
select team, count(1) years
  from (select team, 
        (year -row_number() over (partition by team order by year)) as groupid
          from t1
       ) tmp
group by team, groupid
having count(1) >= 3;

4.2 找出每個id在在一天之內所有的波峰與波谷值

波峰:
這一時刻的值 > 前一時刻的值
這一時刻的值 > 後一時刻的值
波谷:
這一時刻的值 < 前一時刻的值
這一時刻的值 < 後一時刻的值
id time price 前一時刻的值(lag) 後一時刻的值(lead)
sh66688, 9:35, 29.48 null 28.72
sh66688, 9:40, 28.72 29.48 27.74
sh66688, 9:45, 27.74
sh66688, 9:50, 26.75
sh66688, 9:55, 27.13
sh66688, 10:00, 26.30
sh66688, 10:05, 27.09
sh66688, 10:10, 26.46
sh66688, 10:15, 26.11
sh66688, 10:20, 26.88
sh66688, 10:25, 27.49
sh66688, 10:30, 26.70
sh66688, 10:35, 27.57
sh66688, 10:40, 28.26
sh66688, 10:45, 28.03

-- 思路:關鍵是找到波峰波谷的特徵
-- 波峰的特徵: 大於前一個時間段、後一個時間段的值
-- 波谷的特徵: 小於前一個時間段、後一個時間段的值
-- 找到這個特徵SQL就好寫了

select id, time, price,
       case when price > beforeprice and price > afterprice then "波峰"
            when price < beforeprice and price < afterprice then "波谷" end as feature
  from (select id, time, price,
               lag(price) over (partition by id order by time) beforeprice,
               lead(price) over (partition by id order by time) afterprice
          from t2
        )tmp
 where (price > beforeprice and price > afterprice) or
       (price < beforeprice and price < afterprice);

吳邪,小三爺,混跡於後臺,大資料,人工智慧領域的小菜鳥。
更多請關注
file

相關文章