1. 程式人生 > >Hive中靜態分割槽表 & 動態分割槽表

Hive中靜態分割槽表 & 動態分割槽表

概念的引入

在Web系的統日誌表中,當我們的操作很多時,通常所會採取的辦法是:每一次操作都要記錄一條日誌,而這些日誌很多都是按日/月進行分割槽的;如果不這樣做,到時候查起表來回非常非常大。
假設有以下分割槽:
CLICK_LOG_20180801
CLICK_LOG_20180802
CLICK_LOG_20180803
當我們進行這樣進行分割槽之後,對比原來只有一張表CLICK_LOG,會有以下優點:可以提高我們的查詢效率

通過列印的日誌觀察不使用分割槽表所帶來的問題:

hive>select deptno, count(1) from emp group by deptno;

這裡寫圖片描述

列印的資訊中有:
HDFS Read: 8012,表示讀取資料量大小為8012(讀取方式為全表讀取)

我們假設:emp表中有10億條資料
那麼在我們進行全表讀取的時候,效率就會很低

但是當我們使用分割槽表之後,HDFS上資料儲存的目錄就會成為:

/user/hive/warehouse/emp/day=20180808/
/user/hive/warehouse/emp/day=20180809/

而我們去Hive表中查詢資料時,可以這樣寫:

hive>select ... from xxx where day=20180808

從而丟擲Hive中要使用分割槽表的原因:
這樣的操作,可以減少資料的讀取量,進而提升效率

報錯解決方案

在建立Hive表之後,匯入資料的時候,可能會出現報錯:

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Specified key was too long; max key length is 767 bytes

報錯解決方案/亂碼解決辦法:
注意:改變mysql設定,不能改變已經存在的表。我們需要轉換表的編碼。

mysql>alter database 資料庫名稱 character set latin1;
mysql>use 資料庫名稱;
mysql>alter table PARTITIONS convert to
character set latin1; mysql>alter table PARTITION_KEYS convert to character set latin1;

靜態單級分割槽表的使用

從本地匯入資料 & Hive表資料與HDFS資料的區別 & Hive表結構的變化

建立一張表

create table order_partition(
order_number string,
event_time string
)
PARTITIONED BY(event_month string)
row format delimited fields terminated by '\t';

載入資料:

hive>load data local inpath '/opt/data/order_created.txt' overwrite 
     into table order_partition PARTITION(event_month='201405');

資料匯入成功,對比hive中查表得到的資料與hdfs中儲存的資料:

hive>select * from order_partition;

這裡寫圖片描述

$>hadoop fs -text /user/hive/warehouse/order_partition/event_month=201405/order_created.txt

這裡寫圖片描述

發現
在Hive表中,能查到分割槽列的資料,但是在HDFS的資料表中查不到分割槽列的資料
因為:分割槽列不是表中的一個實際的列,其實質是一個偽列,而HDFS中儲存的是真正的資料,因此肯定看不到該列

查看錶結構:

hive>desc formatted order_partition;

多了Partition Information的資訊:
這裡寫圖片描述

從HDFS匯入資料 & 兩種方式修改表的分割槽資訊 & 表的分割槽資訊的查詢

在HDFS上建立相應的目錄,並上傳資料:

$>hadoop fs -mkdir /user/hive/warehouse/order_partition/event_month=201406
$>hadoop fs -put /opt/data/order_created.txt /user/hive/warehouse/order_partition/event_month=201406

HDFS中event_month=201406目錄下,已經傳入資料:
這裡寫圖片描述

但是,出現了一個問題:
雖然,我們在HDFS上添加了event_month=201406的分割槽資料,但是Hive表中的資料卻仍然沒有改變
我們通過查詢Hive表上的資料,驗證發現數據確實沒有新增進來,資料仍然是5條

hive>select * from order_partition;

這裡寫圖片描述

開始查詢原因:
首先,我們對mysql裡的元資料資訊進行查詢:

mysql>use zhaotao_hive;
mysql>select * from PARTITIONS;
mysql>select * from PARTITION_KEYS;

發現mysql中,分割槽資訊並沒有發生改變
這裡寫圖片描述

語法:

ALTER TABLE table_name ADD [IF NOT EXISTS] PARTITION partition_spec [LOCATION 'location'][, PARTITION partition_spec [LOCATION 'location'], ...];
partition_spec:
  : (partition_column = partition_col_value, partition_column = partition_col_value, ...)

修改分割槽資訊:

hive>ALTER TABLE order_partition ADD IF NOT EXISTS PARTITION(event_month='201406'); 

成功解決,再度查詢資料

hive>select * from order_partition;
mysql>select * from PARTITIONS;
mysql>select * from PARTITION_KEYS;

Hive表中的資料:
這裡寫圖片描述

MySQL中的元資料資訊:
這裡寫圖片描述

通過上圖,我們發現數據都進來了,從HDFS中匯入分割槽資料成功

語法:

MSCK REPAIR TABLE table_name;
$>hadoop fs -mkdir /user/hive/warehouse/order_partition/event_month=201407
$>hadoop fs -put /opt/data/order_created.txt /user/hive/warehouse/order_partition/event_month=201407           
hive>MSCK REPAIR TABLE order_partition; 

執行完這句話之後,Hive表中的資料直接進來了,mysql的元資料資訊也增加了
這裡寫圖片描述
這裡寫圖片描述

不建議這樣使用,太暴力了
舉個例子:
metastore存了一年了,5分鐘1個分割槽,1天就是288個分割槽
假設有100條業務線
一旦這樣一執行,可能會造成的情況,就是整個資料庫出現風險
因此,生產上建議使用alter

查詢分割槽資訊

hive>show partitions order_partition;

這裡寫圖片描述
(可以通過查閱原始碼,去驗證show partitions從mysql的哪張表裡來讀取分割槽資料資訊 )

【注意】
如果沒有mysql上的元資料資訊,HDFS上的資料是和hive中執行的sql無法關聯起來的
因此,每次執行一個SQL語句,都必須要知曉底層的metastore到底幹了些什麼事情,這對學習Hive會有很大的幫助

靜態多級分割槽表的使用

建立表

create table order_mulit_partition(
order_number string,
event_time string
)
PARTITIONED BY(event_month string, step string)
row format delimited fields terminated by '\t';

從本地向靜態多級分割槽表匯入資料

hive>load data local inpath '/opt/data/order_created.txt' overwrite 
     into table order_mulit_partition PARTITION(event_month='201405', step='1');

這裡寫圖片描述

注意:在多分割槽使用的時候注意: 每個分割槽欄位要寫明,包括順序等等

動態分割槽表的使用

在Hive中,使用動態分割槽表,這種方式在工作中常用

需求

按照不同部門作為分割槽導資料到目標表

使用靜態分割槽表來完成

建立靜態分割槽表:

create table emp_static_partition(
empno int, 
ename string, 
job string, 
mgr int, 
hiredate string, 
sal double, 
comm double)
PARTITIONED BY(deptno int)
row format delimited fields terminated by '\t';

插入資料:

hive>insert into table emp_static_partition partition(deptno=10)
     select empno , ename , job , mgr , hiredate , sal , comm from emp where deptno=10;

查詢資料:

hive>select * from emp_static_partition;

這裡寫圖片描述

使用動態分割槽表來完成

建立動態分割槽表:

create table emp_dynamic_partition(
empno int, 
ename string, 
job string, 
mgr int, 
hiredate string, 
sal double, 
comm double)
PARTITIONED BY(deptno int)
row format delimited fields terminated by '\t';

【注意】動態分割槽表與靜態分割槽表的建立,在語法上是沒有任何區別的

插入資料:

hive>insert into table emp_dynamic_partition partition(deptno)
     select empno , ename , job , mgr , hiredate , sal , comm, deptno from emp;

【注意】分割槽的欄位名稱,寫在最後,有幾個就寫幾個 與靜態分割槽相比,不需要where了

需要設定屬性的值:

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

這裡寫圖片描述
【注意】不設定,會報錯

查詢資料:

hive>select * from emp_dynamic_partition;

這裡寫圖片描述
分割槽列為deptno,實現了動態分割槽

動態分割槽表的總結

動態分割槽無需手工指定資料匯入的具體分割槽
而是由select的欄位(欄位寫在最後,有幾個寫幾個)自行決定匯出到哪一個分割槽中
並自動建立相應的分割槽,使用上更加方便快捷
工作中用的非常多