深入理解Hive分區(qū)與分桶

概述

目前占业,在利用hive建設數(shù)據(jù)倉庫的過程中,總會遇見分區(qū)分桶的赦肋,跟傳統(tǒng)的DBMS系統(tǒng)一樣块攒,通過表分區(qū)能夠在特定的區(qū)域檢索數(shù)據(jù),減少掃描成本佃乘,在一定程度上提高查詢效率囱井。比如我們要收集某個大型網(wǎng)站的日志數(shù)據(jù),一個網(wǎng)站每天的日志數(shù)據(jù)存在同一張表上趣避,由于每天會生成大量的日志庞呕,導致數(shù)據(jù)表的內(nèi)容巨大劫灶,在查詢時進行全表掃描耗費的資源非常多拓型。那其實這個情況下,我們可以按照日期對數(shù)據(jù)表進行分區(qū)策彤,不同日期的數(shù)據(jù)存放在不同的分區(qū)愁拭,在查詢時只要指定分區(qū)字段的值就可以直接從該分區(qū)查找讲逛。在物理上分區(qū)表會將數(shù)據(jù)按照分區(qū)鍵的列值存儲在表目錄的子目錄中,目錄名=“分區(qū)鍵=鍵值”岭埠。其中需要注意的是分區(qū)鍵的值不一定要基于表的某一列(字段)盏混,它可以指定任意值,只要查詢的時候指定相應的分區(qū)鍵來查詢即可惜论。

分桶與分區(qū)有所不同许赃,它指定分桶表的某一列,讓該列數(shù)據(jù)按照哈希取模的方式隨機来涨、均勻地分發(fā)到各個桶文件中图焰。因為分桶操作需要根據(jù)某一列具體數(shù)據(jù)來進行哈希取模操作,故指定的分桶列必須基于表中的某一列(字段)蹦掐。因為分桶改變了數(shù)據(jù)的存儲方式技羔,它會把哈希取模相同或者在某一區(qū)間的數(shù)據(jù)行放在同一個桶文件中。如此一來便可提高查詢效率卧抗,比如我們要對兩張在同一列上進行了分桶操作的表進行JOIN操作的時候藤滥,只需要對保存相同列值的桶進行JOIN操作即可。同時分桶也可以提高采樣率社裆。

分區(qū)

分區(qū)是為了對表進行合理的管理以及提高查詢效率拙绊,Hive可以將表組織成“分區(qū)”。一個分區(qū)實際上就是表下的一個目錄,一個表可以在多個維度上進行分區(qū)标沪,分區(qū)之間的關(guān)系就是目錄樹的關(guān)系榄攀。Hive(Inceptor)分區(qū)分為靜態(tài)分區(qū)跟動態(tài)分區(qū),詳細介紹如下:

靜態(tài)分區(qū)?????????????????????????????????????

靜態(tài)分區(qū)在插入或者導入的時候需要指定具體的分區(qū)

[if !supportLists]1金句、? [endif]靜態(tài)分區(qū)創(chuàng)建

需要在PARTITIONED BY后面跟上分區(qū)鍵檩赢,類型。例如:

CREATE?TABLE?p_table1(

id int

,name

string

)

PARTITIONED BY(date_day string)

stored as orc

;

這是一級分區(qū)违寞,當然也可以創(chuàng)建多級分區(qū)贞瞒。例如:

CREATE?TABLE? p_table1(

id int

,name string

)

PARTITIONED BY(date_day string, company

string,emp_no string)

stored as orc

;??????????????????????????????????????????????????????????????????????????

下面的實例都是以一級分區(qū)為例。?????????????????????

[if !supportLists]2趁曼、? [endif]靜態(tài)分區(qū)插入數(shù)據(jù)

insert overwrite table p_table1 partition(date_day='2019-07-14')

values(1,'lucy');

或者insert overwrite table p_table1 partition(date_day='2019-07-15')

select 2 as id,'lily' as name;

上面兩個例子都是覆蓋的形式军浆,也就是插入這個分區(qū)之前,會將該分區(qū)數(shù)據(jù)刪除挡闰,再插入新的數(shù)據(jù)乒融,也可以寫成追加的形式:

insert into p_table1

partition(date_day='2019-07-14') values(1,'lucy');

或者insert into e p_table1 partition(date_day='2019-07-15') select 2 as

id,'lily' as name;


[if !supportLists]3、? [endif]靜態(tài)分區(qū)查看分區(qū)

查看所有分區(qū)show partitions p_table1

結(jié)果如下:

date_day=2019-07-14

date_day=2019-07-15

查看某個分區(qū)show partitions p_table1 partition(date_day='2019-07-14');

結(jié)果如下:

date_day=2019-07-14

[if !supportLists]4尿这、? [endif]靜態(tài)分區(qū)刪除分區(qū)

刪除某個分區(qū)alter table p_table1 drop partition(date_day='2019-07-14');

或者刪除范圍內(nèi)的分區(qū)alter table p_table1 drop partition(date_day>='2019-07-14');

動態(tài)分區(qū)

1簇抵、動態(tài)分區(qū)創(chuàng)建

創(chuàng)建方式與靜態(tài)分區(qū)表完全一樣庆杜,一張表可同時被靜態(tài)和動態(tài)分區(qū)鍵分區(qū)射众,只是動態(tài)分區(qū)鍵需要放在靜態(tài)分區(qū)建的后面(因為HDFS上的動態(tài)分區(qū)目錄下不能包含靜態(tài)分區(qū)的子目錄)。

CREATE TABLE p_table2(

id int

,name string

)

PARTITIONED BY(date_day string,emp_no

string)

stored as orc

;

這是創(chuàng)建了二級分區(qū)表晃财。

2叨橱、動態(tài)分區(qū)插入數(shù)據(jù)

插入數(shù)據(jù)時需要開啟動態(tài)數(shù)據(jù)支持:

set hive.exec.dynamic.partition=true;

set hive.exec.dynamic.partition.mode=nostrict;

插入數(shù)據(jù)(覆蓋)insert overwrite table p_table2 partition(date_day,emp_no)

select 2 as id,'lily' as name,'2019-07-14' as date_day, ‘a(chǎn)’ as emp_no;

分區(qū)并沒有寫死断盛,而是根據(jù)查詢到的值動態(tài)創(chuàng)建的兩級分區(qū)罗洗。

3、動態(tài)分區(qū)查看分區(qū)钢猛、刪除分區(qū)與靜態(tài)分區(qū)操作完全一致不再重述伙菜。

分桶

分桶字段是表內(nèi)字段,默認是對分桶的字段進行hash值命迈,然后姆啡疲總的桶數(shù),得到的值則是分區(qū)桶數(shù)壶愤,主要有以下兩點好處:

(1)獲得更高的查詢處理效率淑倾。桶為表加上了額外的結(jié)構(gòu),Hive 在處理有些查詢時能利用這個結(jié)構(gòu)征椒。具體而言娇哆,連接兩個在(包含連接列的)相同列上劃分了桶的表,可以使用 Map 端連接(Map-side join)高效的實現(xiàn)。比如JOIN操作碍讨。對于JOIN操作兩個表有一個相同的列治力,如果對這兩個表都進行了桶操作。那么將保存相同列值的桶進行JOIN操作就可以勃黍,可以大大較少JOIN的數(shù)據(jù)量琴许。


(2)使取樣(sampling)更高效。在處理大規(guī)模數(shù)據(jù)集時溉躲,在開發(fā)和修改查詢的階段榜田,如果能在數(shù)據(jù)集的一小部分數(shù)據(jù)上試運行查詢,會帶來很多方便锻梳。

創(chuàng)建分桶表

先看一下創(chuàng)建分桶表的創(chuàng)建箭券,分桶表的建表有三種方式:直接建表,CREATE TABLE LIKE 和 CREATE TABLE AS SELECT 疑枯,單值分區(qū)表不能用 CREATETABLE

AS SELECT 建表辩块。這里以直接建表為例:

create table b_table1(id int,name string)

clustered by (id) sorted by(id) into 4 buckets stored as textfile;

使用CLUSTERED BY 子句來指定劃分桶所用的列和要劃分的桶的個數(shù),當表分區(qū)時荆永,每個分區(qū)下都會有4個桶废亭。對于map端連接的情況,兩個表以相同方式劃分桶具钥。處理左邊表內(nèi)某個桶的 mapper知道右邊表內(nèi)相匹配的行在對應的桶內(nèi)豆村。因此,mapper只需要獲取那個桶 (這只是右邊表內(nèi)存儲數(shù)據(jù)的一小部分)即可進行連接骂删。這一優(yōu)化方法并不一定要求兩個表必須桶的個數(shù)相同掌动,兩個表的桶個數(shù)是倍數(shù)關(guān)系也可以。用HiveQL對兩個劃分了桶的表進行連接宁玫。

桶中的數(shù)據(jù)可以根據(jù)一個或多個列另外進行排序粗恢。由于這樣對每個桶的連接變成了高效的歸并排序(merge-sort), 因此可以進一步提升map端連接的效率。

向分桶表寫入數(shù)據(jù)

如何保證表中的數(shù)據(jù)都劃分成桶了呢欧瘪?把在Hive外生成的數(shù)據(jù)加載到劃分成桶的表中眷射,當然是可以的。其實讓Hive來劃分桶更容易佛掖。這一操作通常針對已有的表妖碉。

Hive并不檢查數(shù)據(jù)文件中的桶是否和表定義中的桶一致(無論是對于桶的數(shù)量或用于劃分桶的列)。如果兩者不匹配苦囱,在査詢時可能會碰到錯誤或未定義的結(jié)果嗅绸。因此,建議讓Hive來進行劃分桶的操作撕彤。

要向分桶表中填充成員鱼鸠,需要將 hive.enforce.bucketing 屬性設置為 true猛拴。這樣Hive 就知道用表定義中聲明的數(shù)量來創(chuàng)建桶。

下面有個未分桶的用戶表b_user_test蚀狰,數(shù)據(jù)如下:

1??????a

2??????b

3??????c

4??????d

5??????e

6??????f

7??????g

插入語句

INSERT OVERWRITE TABLE b_table1 SELECT *

FROM b_user_test;

查看文件結(jié)構(gòu)

dfs -ls/user/hive/warehouse/bucketed_users;

文件結(jié)構(gòu)如下所示:


?/user/hive/warehouse/b_table1/000000_0

?/user/hive/warehouse/b_table1/000001_0

?/user/hive/warehouse/b_table1/000002_0

?/user/hive/warehouse/b_table1/000003_0

查看文件000000_0

dfs -cat /user/hive/warehouse/bucketed_users/000000_0;

值為4 d說明文件000000_0存的是對分桶數(shù)求余等于0的那部分數(shù)據(jù)愉昆。

對桶中的數(shù)據(jù)進行采樣

對分桶進行查詢 tablesample(bucket x out of y on id):

x:表示查詢那個桶

y:表示建表指定的桶的總數(shù),如果不是建表時指定的桶的總數(shù),則會重新分桶麻蹋。

x不能大于y跛溉。

取第一個桶的數(shù)據(jù):

Sql:SELECT * FROM

b_table1 TABLESAMPLE(BUCKET 2 OUT OF 4 ON id);

結(jié)果:

5??????e

[if !supportLists]1???????????????????????[endif]a


當桶數(shù)不等于建表指定的桶的總數(shù)時

Sql:SELECT * FROM

b_table1 TABLESAMPLE(BUCKET 2 OUT OF 3 ON id);

結(jié)果:

4??????d

1??????a

7??????g

由結(jié)果可知,進行了重新分桶扮授,分成了三個桶芳室,取出第二個桶的數(shù)據(jù),也就是hash值對3求余等于1的那部分數(shù)據(jù)刹勃。

分桶比分區(qū)粒度更細堪侯,在每個分區(qū)了可以將數(shù)據(jù)進行分桶操作。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荔仁,一起剝皮案震驚了整個濱河市伍宦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乏梁,老刑警劉巖次洼,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異遇骑,居然都是意外死亡卖毁,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門质蕉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來势篡,“玉大人,你說我怎么就攤上這事模暗。” “怎么了念祭?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵兑宇,是天一觀的道長。 經(jīng)常有香客問我粱坤,道長隶糕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任站玄,我火速辦了婚禮枚驻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘株旷。我一直安慰自己再登,他們只是感情好尔邓,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锉矢,像睡著了一般梯嗽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沽损,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天灯节,我揣著相機與錄音,去河邊找鬼绵估。 笑死炎疆,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的国裳。 我是一名探鬼主播磷雇,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼躏救!你這毒婦竟也來了唯笙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤盒使,失蹤者是張志新(化名)和其女友劉穎崩掘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體少办,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡苞慢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了英妓。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挽放。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蔓纠,靈堂內(nèi)的尸體忽然破棺而出辑畦,到底是詐尸還是另有隱情,我是刑警寧澤腿倚,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布纯出,位于F島的核電站,受9級特大地震影響敷燎,放射性物質(zhì)發(fā)生泄漏暂筝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一硬贯、第九天 我趴在偏房一處隱蔽的房頂上張望焕襟。 院中可真熱鬧,春花似錦饭豹、人聲如沸鸵赖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卫漫。三九已至菲饼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間列赎,已是汗流浹背宏悦。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留包吝,地道東北人饼煞。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像诗越,于是被迫代替她去往敵國和親砖瞧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容