Hive中靜態分區和動態分區總結

目錄

  • 背景
  • 第一部分 靜態分區
  • 第二部分 動態分區
  • 第三部分 兩者的比較
  • 第四部分 動態分區使用的問題
  • 參考文獻及資料

背景

Hive中有兩種類型的分區:靜態分區(Static Partitioning)和動態分區(Dynamic Partitioning)。

  • 靜態分區。對於靜態分區,從字面就可以理解:表的分區數量和分區值是固定的。
  • 動態分區。會根據數據自動的創建新的分區。

本文會詳細介紹兩種分區方法、使用場景以及生產中常見問題和解決方法。

第一部分 靜態分區

靜態分區的使用場景主要是分區的數量是確定的。例如人力資源信息表中使用「部門」作為分區字段,通常一段時間是靜態不變的。例如:

CREATE EXTERNAL TABLE employee_dept (
    emp_id INT,
    emp_name STRING
) PARTITIONED BY (
    dept_name STRING
    )
location '/user/employee_dept';

LOAD DATA LOCAL INPATH 'hr.txt'
INTO TABLE employee_dept
PARTITION (dept_name='HR');

上面的外部表以dept_name字段為分區字段,然後導入數據需要指定分區。

第二部分 動態分區

通常在生產業務場景中,我們使用的都是靈活的動態分區。例如我們使用時間字段(天、小時)作為分區字段。新的數據寫入會自動根據最新的時間創建分區並寫入對應的分區。例如下面的例子:

hive > insert overwrite table order_partition partition (year,month) select order_id, order_date, order_status, substr(order_date,1,4) year, substr(order_date,5,2) month from orders;

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

寫入報錯。這是因為Hive默認配置不啟用動態分區,需要使用前開啟配置。開啟的方式有兩種:

  • 在hive服務配置文件中全局配置;

  • 每次交互時候進行配置(隻影響本次交互);

通常我們生產環境使用第二種。

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

其中參數hive.exec.dynamic.partition.mode表示動態分區的模式。默認是strict,表示必須指定至少一個分區為靜態分區,nonstrict模式表示允許所有的分區字段都可以使用動態分區。

第三部分 兩者的比較

兩種分區模式都有各自的使用場景,我們總結如下:

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

另外動態分區的值是MapReduce任務在reduce運行階段確定的,也就是所有的記錄都會distribute by,相同字段(分區字段)的map輸出會發到同一個reduce節點去處理,如果數據量大,這是一個很弱的運行性能。而靜態分區在編譯階段就確定了,不需要reduce任務處理。所以如果實際業務場景靜態分區能解決的,盡量使用靜態分區即可。

第四部分 動態分區使用的問題

Hive表中分區架構使得數據按照分區分別存儲在HDFS文件系統的各個目錄中,查詢只要針對指定的目錄集合進行查詢,而不需要全局查找,提高查詢性能。

但是分區不是”銀彈”,如果分區數據過多,就會在HDFS文件系統中創建大量的目錄和文件,對於集群NameNode服務是有性能壓力的,NameNode需要將大量元數據信息保留在內存中。另外大分區表在用戶查詢時候由於分析size太大,也容易造成Metastore服務出現OMM報錯。

上面兩個現象均在生產環境發生,分別造成NameNodeMetastore不可用。

事實上,Hive為了防止異常生產大量分區,甚至默認動態分區是關閉的。另外對於生成動態分區的數量也做了性能默認限制。

4.1 動態分區創建限制

當我們在一個Mapreduce任務(hive寫入會編譯成mapreduce任務)中創建大量分區的時候,經常會遇到下面的報錯信息:

2015-06-15 17:27:44,614 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

這個報錯就是因為Hive對於動態分區創建的限制,涉及的參數有:

hive.exec.max.dynamic.partitions = 1000;
hive.exec.max.dynamic.partitions.pernode = 100;
hive.exec.max.created.files = 10000
  • hive.exec.max.dynamic.partitions.pernode,參數限制MapReduce任務單個任務(mapper或reducer任務)創建的分區數量為100;
  • hive.exec.max.dynamic.partitions,參數限制單次整體任務創建分區的數量上限為1000個;
  • hive.exec.max.created.files,參數限制所有單次整體map和reduce任務創建的最大文件數量上限為10000個;

以上三個閥值超過就會觸發錯誤,集群會殺死任務。為了解決報錯,我們通常將兩個參數調大。但是也需要用戶對自己的Hive表的分區數量進行合理規劃,避免過多的分區。

4.2 特殊分區

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

用戶可以使用(查看錶分區)命令進行查看:

show partitions 'table名稱';

# process_date=20160208
#process_date=__HIVE_DEFAULT_PARTITION__

有時候異常生產這些分區數據,需要進行清理。如果使用下面的語句:

ALTER TABLE Table_Name DROP IF EXISTS PARTITION(process_date='__HIVE_DEFAULT_PARTITION__');

這時候Hive會報錯:

Error: Error while compiling statement: FAILED: SemanticException Unexpected unknown partitions for (process_date = null) (state=42000,code=40000)

這是Hive一個已知bug(編號:HIVE-11208),在Hive 2.3.0版本修復。

但是有個有修復方法(不建議在生產環境中實施):

-- update the column to be "string"
ALTER TABLE test PARTITION COLUMN (p1 string);
-- remove the default partition
ALTER TABLE test DROP PARTITION (p1 = '__HIVE_DEFAULT_PARTITION__');
-- then revert the column back to "int" type
ALTER TABLE test PARTITION COLUMN (p1 int);

鏈接://cloudera.ericlin.me/2015/07/how-to-drop-hives-default-partition-hive_default_partition-with-int-partition-column/

4.3 亂碼分區字段

有時候表分區字段由於處理不當,會出現亂碼分區,例如:

hp_stat_time=r_ready%3D91;r_load%3D351

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

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

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

參考文獻及資料

1、動態分區,鏈接://cwiki.apache.org/confluence/display/Hive/DynamicPartitions

2、Hive Tutorial,鏈接://cwiki.apache.org/confluence/display/Hive/Tutorial

3、Apache Hive 中文手冊,鏈接://www.docs4dev.com/docs/zh/apache-hive/3.1.1/reference

更多關注公眾號:
image

Tags: