什麼是hive的靜態分區和動態分區,它們又有什麼區別呢?hive動態分區詳解

面試官問我,什麼是hive的靜態分區和動態分區,這題我會呀。

簡述

分區是hive存放數據的一種方式,將列值作為目錄來存放數據,就是一個分區,可以有多列。

這樣查詢時使用分區列進行過濾,只需根據列值直接掃描對應目錄下的數據,不掃描不關心的分區,快速定位,提高查詢效率。

hive的分區有兩種類型:

  • 靜態分區SP(Static Partitioning)
  • 動態分區DP(Dynamic Partitioning)

對於靜態分區,表的分區數量和分區值是固定的。新增分區或者是載入分區數據時,需要提前指定分區名。

對於動態分區,分區的值是不確定的,會根據數據自動的創建新的分區。

一、靜態分區

如上所述,靜態分區的使用場景主要是分區的數量是確定的。例如日誌流水數據中使用日期作為分區欄位,通常在寫入之前就已經確定了是哪個分區。

1.單分區建表

create table if not exists day_log(
  uid bigint,
  uname string,
  action string
) comment '用戶動作流水記錄'
partitioned by(ymd string comment '日期格式yyyyMMdd')
row format delimited fields terminated by '\t';

2.載入數據到指定分區

load data local inpath '/user/hive/data/day_log.txt' 
into table day_log paritition(ymd='20220803')

3.創建具有多個分區的表

create table if not exists day_log(
  uid bigint,
  uname string,
  action string
) comment '用戶動作流水記錄'
partitioned by(year string,month string,day string)
row format delimited fields terminated by '\t';

4.載入數據

load data local inpath '/user/hive/data/day_log.txt' 
into table day_log paritition(year='2022',month='08',day='02')

但通常我們寫入分區數據是通過計算SQL結果直接寫入,並不是從外部文件load進來的。示例如下:

insert overwrite table day_log partition (year='2022',month='08',day='02')
select uid,uname,action from (
	xxxxxx
)

二、動態分區

所謂動態分區,分區的值是不確定的,分區的數量是不確定,皆由載入數據確定。
生產環境中,動態分區一般常用於創建新表後,需要一次性載入歷史數據。

1.創建臨時表

-- 創建臨時表
create table if not exists tmp (
  uid int,
  commentid bigint,
  recommentid bigint,
  year int,
  month int,
  day int
)
row format delimited fields terminated by '\t';

-- 載入數據到臨時表
load data local inpath 'user/hive/data/tmp.txt' into table tmp;

2.創建動態分區表

-- 創建動態分區表
create table if not exists dp_tmp(
	uid int,
	commentid bigint,
	recommentid bigint
)
partitioned by (year string,month string,day string)
row format delimited fields terminated by '\t';

-- 寫入數據到分區表
-- 參數為開啟動態分區
set hive.exec.dynamic.partition=true;
insert overwrite table dp_tmp partition(year,month,day)
select uid,commentid,recommentid,year,month,day from tmp;

執行上述寫入語句會報錯:

FAILED: SemanticException [Error 10096]: Dynamic partition strict mode requires at least one static partition column. To turn this off set hive.exec.dynamic.partition.mode=nonstrict

看報錯資訊:動態分區嚴格模式至少需要一個靜態分區列。關閉它,設置參數

set hive.exec.dynamic.partition.mode=nonstrict

下文介紹hive相關參數作用

3.嚴格模式

參數hive.exec.dynamic.partition.mode表示動態分區的模式。
默認是strict,也就是嚴格模式,表示必須指定至少一個分區為靜態分區

nonstrict模式,即非嚴格模式,表示允許所有的分區欄位都可以使用動態分區

嚴格模式

-- 至少需要指定一個靜態分區列
-- 開啟動態分區
set hive.exec.dynamic.partition=true;
insert overwrite table dp_tmp partition(year='2022',month,day)
select uid,commentid,recommentid,month,day from tmp;

4.非嚴格模式

set hive.exec.dynamic.partition=true;
-- 允許所有的分區欄位都可以使用動態分區,兼容嚴格模式
-- 更改動態分區模式為非嚴格模式
set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table dp_tmp partition(year,month,day)
select uid,commentid,recommentid,month,day from tmp;

通常情況下,我們使用動態分區,為非嚴格模式:

 set hive.exec.dynamic.partition=true;
 set hive.exec.dynamic.partition.mode=nonstrict;

三、靜態分區和動態分區的區別

兩種分區模式根據定義就可看出來明顯區別,這裡單列一下:

靜態分區(Static Partitioning) 動態分區(Dynamic Partitioning)
分區創建 數據插入分區之前,需要手動指定創建每個分區 根據表的輸入數據動態創建分區
適用場景 需要提前知道所有分區。適用於分區定義得早且數量少的用例,常見為插入某一個指定分區 有很多分區,無法提前預估新分區,動態分區是合適的

另外動態分區的值是MapReduce任務在reduce運行階段確定的,也就是所有的記錄都會distribute by,相同欄位(分區欄位)的map輸出會發到同一個reduce節點去處理,如果數據量大,這是一個很弱的運行性能。

而靜態分區在編譯階段就確定了,不需要reduce任務處理。所以如果實際業務場景靜態分區能解決的,盡量使用靜態分區即可。

四、分區使用注意事項

1.hive分區參數及作用

hive表中的分區作用主要是使數據按照分區目錄存儲在hdfs上,查詢只要針對指定的目錄集合進行查詢,避免全局查找,這樣提高了查詢性能。

hive的分區需要合理使用,過多的分區目錄和文件對於集群Namenode服務是有性能壓力的,Namenode需要將大量的元數據資訊保存在記憶體中。如果報錯,會造成Namenode不可用。

一次查詢表裡有太多分區,會使得查詢文件過大,也會造成Metastore服務出現OOM報錯,報錯資訊顯示Metastore不可用。

hive為了避免因為異常產生大量分區,導致上述問題,本身是默認動態分區關閉,同時對生成動態分區的數量也做了一定限制。

通過手動參數設置可以改變系統默認值,具體hive默認參數以及SQL執行配置參數(不同版本默認參數有一定差異)如下:

-- Hive默認配置值
-- 開啟或關閉動態分區
hive.exec.dynamic.partition=false;
-- 設置為nonstrict模式,讓所有分區都動態配置,否則至少需要指定一個分區值
hive.exec.dynamic.partition.mode=strict;
-- 能被mapper或reducer創建的最大動態分區數,超出而報錯
hive.exec.max.dynamic.partitions.pernode=100;
-- 一條帶有動態分區SQL語句所能創建的最大動態分區總數,超過則報錯
hive.exec.max.dynamic.partitions=1000;
-- 全局能被創建文件數目的最大值,通過Hadoop計數器跟蹤,若超過則報錯
hive.exec.max.created.files=100000;

-- 根據個人需要配置
-- 設置動態分區開啟
set hive.exec.dynamic.partition=true;  
-- 設置為非嚴格模式
set hive.exec.dynamic.partition.mode=nonstrict;
-- 設置每個節點創建最大分區數
set hive.exec.max.dynamic.partitions.pernode=1000;
-- 設置執行SQL創建最大分區數
set hive.exec.max.dynamic.partitions=10000;
-- 設置全局被創建文件最大值
set hive.exec.max.created.files=1000000;

在執行hiveSQL的時候如果動態分區數量或文件數任何一個超過集群默認就會產生報錯:

ERROR [LocalJobRunner Map Task Executor #0]:mr.ExecMapper (ExecMapper.java:map(171)) - org.apache.hadoop.hive.ql.metadata.HiveException: Hive Runtime Error while processing row ....
 Caused by: org.apache.hadoop.hive.ql.metadata.HiveFatalException: [Error 20004]: Fatal error occurred when node tried to create too many dynamic partitions. The maximum number of dynamic partitions is controlled by hive.exec.max.dynamic.partitions and hive.exec.max.dynamic.partitions.pernode. Maximum was set to: 256... 10 more

集群會kill任務。為了解決報錯,我們通常將三個參數調大。但是也需要用戶對自己的Hive表的分區數量進行合理規劃,避免過多的分區

2.分區常見注意事項

a. 盡量不要使用動態分區,因為動態分區的時候,將會為每一個分區分配reducer數量,當分區數量多的時候,reducer數量將會增加,對伺服器是一種災難。

b. 動態分區和靜態分區的區別,靜態分區不管有沒有數據都會創建指定分區,動態分區是有結果集將創建,否則不創建。

c. hive動態分區的嚴格模式和hive嚴格模式是不同的。

hive提供的嚴格模式簡述:
hive提供的嚴格模式,為了組織用戶不小心提交惡意SQL
hive.mapred.mode=nostrict : strict
如果該模式值為strict,將會阻止一下三種查詢:
a.對分區表查詢,where條件中過濾欄位沒有分區欄位;
b.笛卡爾積join查詢,join查詢語句中不帶on條件或者where條件;
c.對order by查詢,有order by的查詢不太limit語句。

3.一些異常分區處理

a.默認分區

如果動態分區列輸入的值為NULL或空字元串,則hive將該行放入一個特殊分區,分區名稱由參數hive.exec.default.partition.name控制。

默認值為__HIVE_DEFAULT_PARTITION__。可以通過查看錶分區命令進行查看:

show partitions 'table';
  
-- ymd=__HIVE_DEFAULT_PARTITION__

清理該分區使用正常刪除分區語句即可。對分區的操作命令詳見上篇文章。

b.亂碼分區

表分區欄位處理不當可能會造成亂碼分區,主要是由於轉譯編碼原因造成。例如:

sp_test=r_ready%3D91;r_load%3D351

原因是Hive會自動對一些UTF-8字元編碼成Unicode(類似網址中中文字元和一些特殊字元的編碼處理)。此處%3D解碼後是’=’。可以使用在線轉換進行解碼://www.matools.com/code-convert-utf8。

最後使用解碼後的欄位即可(注意分號轉義):

alter table dpdw_traffic_base drop partition(sp_test='r_ready=91\;r_load=351');

上一篇:關於hive分區,你知道多少呢?

按例,我的個人公眾號:魯邊社,歡迎關注
魯邊社

後台回復關鍵字 hive,隨機贈送一本魯邊備註版珍藏大數據書籍。

Tags: