一文徹底學會hive分桶表(實戰詳解)

一、分桶表概述

1.1、什麼是分桶表?

分桶是將數據集分解成更容易管理的若干部分的一個技術,是比表或分區更爲細粒度的數據範圍劃分。針對某一列進行桶的組織,對列值哈希,然後除以桶的個數求餘,決定將該條記錄存放到哪個桶中。

常用於:

  • 獲得更高的查詢處理效率
  • 抽樣調查
1.2、分桶表和分區表有啥區別?

分區表提供了一個隔離數據和優化查詢的便利方式。但是在實際場景下,並非所有的數據集都可形成合理的分區。對於一張表或者分區,Hive還可以進一步組織成桶,也就是更爲細粒度的數據範圍劃分。

小結一波:

  1. 分桶對數據的處理比分區更加細粒度化;
  2. 分桶和分區兩者不干擾,可以把分區表進一步分桶;
  3. 分區針對的是數據的存儲路徑;分桶針對的是數據文件。

二、分桶表實戰

首先說明一下,我的hive環境是基於docker-compose構建,使用postgresql管理metastore,各重要組件版本如下:

hadoop:2.7.4

hive:2.3.2

java:1.8

其實環境不重要,不用花太多時間,主要還是技術部分,接下來就開始實戰吧。

2.1、創建一個分桶表

我們創建一個簡單的分桶表,只有兩個字段(id,name),並且按照id進行分6個桶,sql如下:

create table test_buck(id int, name string)
clustered by(id) 
into 6 buckets
row format delimited fields terminated by '\t';

執行並查看錶結構:
創建分桶表並查看錶結構

使用desc formatted test_buck;查看test_buck表結構,數據較多,這裏截取重要數據如下:
分桶表結構重要數據

2.2、準備數據

準備一些編號和字符串並按照 "\t"分隔開,把這些數據放入/tools/目錄下的test_buck.txt文件內,數據格式如下圖:
數據樣式

2.3、向分桶表導入數據
2.3.1、錯誤導入示範(引出分桶的本質)

數據準備好之後,我們就可以向分桶表裏導入數據裏。這裏我首先使用如下常規命令導入:

load data local inpath '/tools/test_buck.txt' into table test_buck;

然後很驚奇的是它報錯了,報錯信息如下:
報錯信息

簡單翻譯一下,報錯信息是這樣說的:請把數據導入到一箇中間表,並使用insert … select語句導入到分桶表裏。如果你非要直接導入分桶表裏,需要把hive.strict.checks.bucketing設置爲false(關閉嚴格模式),然後你寫sql就沒有檢查了。。。。。

哈哈,到這裏,我們知道了分桶表應該怎麼導入數據了,但是爲啥直接導入就不行呢?下面讓我們硬着頭皮改爲false,然後導入數據試一下。

set hive.strict.checks.bucketing = false;

取消嚴格模式並插入數據
然後我們打開50070查看hdfs上數據如下:

查看結果數據
說好的分6個桶呢?爲什麼只有一個呢?

這是因爲:

桶的概念就是MapReduce的分區的概念,兩者是完全一樣的。也就是說物理上每個桶就是目錄裏的一個文件,一個作業產生的桶(輸出文件)數量和reduce任務個數相同

所以這裏我們導入一個文件,由於分區數等於文件數,只有一個分區,所以上面的操作並沒有分桶。

2.3.2、正確導入示範(引出分桶規則)

繞了一圈,感覺還是把hive.strict.checks.bucketing設置爲true比較好,節省犯錯成本(不過有時候多犯錯也是好事,比如上面咱們至少知道了hive分桶本質上就是mapreduce的分區)。

把hive嚴格模式打開,並把桶表清空:

set hive.strict.checks.bucketing = true;
truncate table test_buck;

下面我們使用之前嚴格模式下建議我們使用的分桶表導入數據方式,使用中間表來進行數據導入:

  1. 設置強制分桶爲true,並設置reduce數量爲分桶的數量個數。

    set hive.enforce.bucketing = true;
    

    啓用強制分桶

  2. 創建一個臨時表,並導入數據。

    create table temp_buck(id int, name string)
    row format delimited fields terminated by '\t';
    load data local inpath '/tools/test_buck.txt' into table temp_buck;
    

    創建臨時表並導入數據

  3. 使用insert select來間接把數據導入到分桶表。

    insert into table test_buck select id, name from temp_buck;
    
  4. 在50070上查看分桶表的數據,已經分爲了6個,桶表數據插入成功!
    分桶數據

  5. 查詢分桶表裏的數據。

    select * from test_buck;
    

    結果如下圖,仔細觀察:
    查詢分桶表的數據

通過觀察規則和桶數的對應關係,我們可以得出如下分桶規則

  • Hive的分桶採用對分桶字段的值進行哈希,然後除以桶的個數求餘的方式決定該條記錄存放在哪個桶當中
2.4、分桶抽樣

對錶分桶一般有兩個目的,提高數據查詢效率、抽樣調查。通過前面的實戰,我們已經可以對分桶表進行正常的創建並導入數據了。一般在實際生產中,對於非常大的數據集,有時用戶需要使用的是一個具有代表性的查詢結果而不是全部結果。這個時候Hive就可以通過對錶進行抽樣來滿足這個需求。

抽樣語句語法解析:

tablesample(bucket x out of y)
y必須是table總bucket數的倍數或者因子。hive根據y的大小,決定抽樣的比例。
例如,table總共分了6份,當y=2時,抽取(6/2=)3個bucket的數據,當y=8時,抽取(6/8=)3/4個bucket的數據。
x表示從哪個bucket開始抽取,如果需要取多個分區,以後的分區號爲當前分區號加上y。
例如,table總bucket數爲6,tablesample(bucket 1 out of 2),表示總共抽取(6/2=)3個bucket的數據,抽取第1(x)個和第3(x+y)個和第5(x+y)個bucket的數據。
注意:x的值必須小於等於y的值

舉例:

select * from test_buck tablesample(bucket 1 out of 3 on id);

結果如下圖,可以發現,上面這條sql查出了第1個和第4個桶的數據:
抽樣結果數據

三、總結

3.1、分桶表的優點
  1. 查詢效率更快,因爲分桶爲表加上了額外結構,鏈接相同列劃分了桶的表,可以使用map-side join更加高效;
  2. 由於分桶規則保證了數據在不同桶的隨機性,因此平時進行抽樣調查時取樣更加方便。
3.2、常用操作
  1. 建表語句及含義

    create table buck_table_name (id int,name string)
    clustered by (id) sorted by (id asc) into 4 buckets
    row format delimited fields terminated by '\t';
    注意:CLUSTERED BY來指定劃分桶所用列和劃分桶的個數。
    分桶規則:HIVE對key的hash值除bucket個數取餘數,保證數據均勻隨機分佈在所有bucket裏。
    SORTED BY對桶中的一個或多個列另外排序
    
  2. 導入數據

    先把數據導入中間表,然後使用insert select語句進行間接導入到分桶表,比如咱們實戰的例子:

    insert into table test_buck select id, name from temp_buck;
    
3.3、分桶表的實質及與分區表的區別

hive的桶其實就是MapReduce的分區的概念,兩者完全相同。在物理上每個桶就是目錄裏的一個文件,一個作業產生的桶(輸出文件)數量和reduce任務個數相同。

分區代表了數據的倉庫,也就是文件夾目錄。每個文件夾下面可以放不同的數據文件。通過文件夾可以查詢裏面存放的文件。但文件夾本身和數據的內容毫無關係。

桶則是按照數據內容的某個值進行分桶,把一個大文件散列稱爲一個個小文件。這些小文件可以單獨排序。如果另外一個表也按照同樣的規則分成了一個個小文件。兩個表join的時候,就不必要掃描整個表,只需要匹配相同分桶的數據即可,效率當然大大提升。

同樣的道理,在對數據抽樣的時候,也不需要掃描整個文件。只需要對每個分區按照相同規則抽取一部分數據即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章