Hive SQL之分區表與分桶表


  Hive sql是Hive 用戶使用Hive的主要工具。Hive SQL是類似於ANSI SQL標准的SQL語言,但是兩者有不完全相同。Hive SQL和Mysql的SQL方言最為接近,但是兩者之間也存在着顯著的差異,比如Hive不支持行級數據的插入、更新和刪除,也不支持事務操作。

  注: HIVE 2.*版本之后開始支持事務功能,以及對單條數據的插入更新等操作

Hive的相關概念

  • Hive數據庫

     Hive中的數據庫從本質上來說僅僅就是一個目錄或者命名空間,但是對於具有很多用戶和組的集群來說,這個概念非常有用。首先,這樣可以避免表命名沖突;其次,它等同於與關系型數據庫中數據庫的概念,是一組表或者表的邏輯組,非常容易理解

  • Hive表

    Hive中的表和關系型數據庫中table概念是類似的,每個table在Hive中都有一個相應的目錄存儲數據。如果說,你沒有指定表的數據庫,那么Hive會通過{HIVE_HOME}/conf/hive_site.xml配置文件中的hive.metastore.warehouse.dir屬性來使用默認值(一般是/usr/hive/warehouse,也可以根據實際情況來進行修改該配置),所有的table都保存在這個目錄中。

    Hive中的表分為兩類,分別為內部表外部表

    • 內部表(managed table)

      內部表,也即Hive管理的表,Hive內部表的管理包括邏輯以及語法上的,也包含實際物理意義上的,也就是說,創建Hive內部表后,表中的數據實際上是存儲在表所在的目錄內,由Hive本身來管理,什么意思呢?也就是說,如果你想刪除表的話,那么,連同表的物理數據,元數據等會一並刪除。舉個栗子:

  create table managed_table(name string,age int);
  load data inpath '/hadoop/guozy/data/user.txt' into table managed_table;

  第一條語句,創建一張簡單的內部表,

  第二條語句,將hdfs://hadoop/guozy/data/user.tx 移動到Hive對應的目錄hdfs://user/hive/warehouse/managed_table/這個目錄中。注意,這里是移動,並非復制

  移動數據是非常快的,因為Hive不會對數據是否符合定義的Schema做校驗,這個工作通常在讀取的時候進行(即Schema on Read),此時我們在執行刪除操作:

drop table managed_table;

  在執行這條語句之后,其物理數據和表的元數據都會被刪除。    

    • 外部表(external table)

      相對於內部表來說,其管理僅僅是在邏輯和語法意義上的,實際的數據並非由Hive本身來管理,而是交給了HDFS。當創建一個外部表的時候,僅僅是指向一個外部目錄而已。如果你想刪除表,只是刪除表的元數據信息,並不會對實際的物理數據進行刪除。舉個栗子:

create external table external_table (name string,age int) location '/hadoop/guozy/external_table';
load data inpath '/hadoop/guozy/data/user.txt' into table external_table;

  第一條語句,創建一張簡單的外部表,這里與內部表的區別是,添加了關鍵字external和location數據位置

  第二條語句,向表中載入數據,會將hdfs://hadoop/guozy/data/user.tx 移動到Hive對應的目錄hdfs://hadoop/guozy/external_table這個目錄中

  對於Hive來說,它不會校驗外部表的數據目錄是否存在。所以我們完全可以在創建表之后在創建數據。此時我們在來刪除該表:

drop table external_table;

  執行上面這條語句之后,Hive刪除的僅僅是該表對應的元數據而已,並不會對實際的屋里數據進行刪除,也就是說hdfs://hadoop/guozy/external_table這個目錄下的數據不會被刪除。

  • 分區和分桶

    Hive將表划分為分區(partition)表和分桶(bucket)表。

    分區可以讓數據的部分查詢變得更快,也就是說,在加載數據的時候可以指定加載某一部分數據,並不是全量的數據。

    分桶表通常是在原始數據中加入一些額外的結構,這些結構可以用於高效的查詢,例如,基於ID的分桶可以使得用戶的查詢非常的塊。

    • 分區表 

      所謂的分區表,指的就是將數據按照表中的某一個字段進行統一歸類,並存儲在表中的不同的位置,也就是說,一個分區就是一類,這一類的數據對應到hdfs存儲上就是對應一個目錄。當我們需要進行處理的時候,可以通過分區進行過濾,從而只去部分數據,而沒必要取全部數據進行過濾,從而提升數據的處理效率。且分區表是可以分層級創建。

      分區表又分為靜態分區表動態分區表兩種:

      • 靜態分區表:所謂的靜態分區表指的就是,我們在創建表的時候,就已經給該表中的數據定義好了數據類型,在進行加載數據的時候,我們已經知道該數據屬於什么類型,並且直接加載到該分區內就可以了。來看一個簡單的分區表的創建語句(這里創建的是一張內部表):
hive> create table enter_country_people(id int,name string,cardNum string) partitioned by (enter_date string,country string);

         指定分區表關鍵字:partitioned by 

            這里的分區字段為:enter_date、country,也就是說,先按照enter_date進行分類,在enter_date的基礎上,在按照country再次進行分類

         注意,這里的分區字段不能包含在表定義字段中,因為在向表中load數據的時候,需要手動指定該字段的值。

        接下來向表中載入數據,並且指定分區為enter_date='2019-01-02',country='china' 

hive> load data inpath '/hadoop/guozy/data/enter__china_people' into table enter_country_people partition (enter_date='2019-01-02',country='china');

         這樣創建表之后的表目錄結構是這樣的:

        

        這里還有一個問題就是,涉及到載入數據的方式

        1、使用的是load命令,也就是我上面的方式,可以看到,在load數據之前,表中是沒有這個分區(enter_date='2019-01-02',country='china')的。當執行了load命令之后,hive會自動創建該分區。這只是其中的一種方式,還有一種方式就是,我們直接可以通過移動數據到該分區的目錄下

        2、直接通過hdfs的mv命令移動數據到該分區指定的目錄下。因為前面說過,所謂的分區只是對應到hdfs存儲中的一個目錄而已。最終數據查詢還是要到這個目錄中去進行查詢數據。但是這種方式有個前提就是,該分區所在的目錄必須呀提前存在,注意,這里說的是對應的該目錄存在。當然這個目錄你可以手動mkdir,也可以通過hive添加分區的方式進行創建,這里又分為兩種情況:

          a.通過hive添加分區的方式進行創建,例如:

hive> alter table enter_country_people add if not exists partition (enter_date='2019-01-03',country='US');

           通過這種方式添加分區之后,會生成這樣一個目錄:hdfs://user/hive/warehouse/2019-01-03/US,此時,我們就可以直接使用hdfs的mv或cp命令將數據摟到該目錄下。之后使用hive命令進行查詢即可

          b.第二種方式就是,我們先手動創建該目錄:hdfs dfs -mkdir /user/hive/warehouse/2019-01-03/US,然后同樣使用上面這種方式,將數據mv或cp到該目錄下,但是,如果只是這樣的話,你去使用hive命令查詢數據,發現查不到,為什么,因為hive查詢數據是需要先到元數據表中找到對應數據的分區索引的,然后根據找到的分區索引,再去對應的目錄中查找,但是才是我們根本沒有對hive的元數據進行操作,所以元數據中沒有這個分區的信息,所以此時,我們需要在增加一步操作,就是將該分區的信息添加到元數據庫中,我們使用hive的分區修復命令即可:

hive> msck repair table enter_country_people;

           執行上述命令之后,然后在進行數據查詢,就沒有什么問題了

      • 動態分區表:所謂的動態分區表,其實建表方式跟靜態分區表沒有區別,最主要的區別是在載入數據的時候,靜態分區表我們載入數據之前必須保證該分區存在,並且我么已經明確知道載入的數據的類型,知道要將數據加載到那個分區當中去,而動態分區表,在載入的時候,我們事先並不知道該條數據屬於哪一類,而是需要hive自己去判斷該數據屬於哪一類,並將該條數據加載到對應的目錄中去。建表語句跟靜態分區表的建表語句相同,這里不再贅述,主要來看看數據的加載:

        對於動態分區表數據的加載,我們需要先開啟hive的非嚴格模式,並且通過insert的方式進行加載數據

hive> set hive.exec.dynamic.partition.mode=nonstrict;
hive> insert into table enter_country_people(user string,age int) partition(enter_date,country) select user,age,enter_date,country from enter_country_people_bak;

        注意:1、必須先開啟動態分區模式為非嚴格模式

           2、這里在指定分區的時候,並沒有指定具體分區的值,而只是指定的分區的字段

           3、partition中的字段其實是作為插入目標表中的一個字段,所以在從另外一張表select的時候必須查詢字段中包含索要分區的這個字段。

    • 分桶表

        在表或者分區中使用分桶通常有兩個原因,一個是為了高效的查詢,另一個則是為了高效的抽樣。

        桶其實是在表中加入了特殊的結構,hive在查詢的時候可以利用這些結構來提高查詢效率。比如,如果兩個表根據相同的字段進行分桶,則在對這兩個表進行關聯的時候可以使用map-side關聯高效實現。前提是,關聯的字段在分桶字段中出現才可以。先看下hive的分桶建表語句:

hive> create table user_bucket(id int comment 'ID',name string comment '姓名',age int comment '年齡') comment '測試分桶' clustered by (id) sorted by (id) into 4 buckets row format delimited fields terminated by '\t';

        上述語句,指定根據id字段進行分桶,並且分為4個桶,並且每個桶內按照id字段升序排序,如果不加sorted by,則桶內不經過排序的,具體的分桶規則是怎樣的呢?Hive是根據指定的分桶字段,上述語句中為id,根據id進行hash之后在對分桶數量4進行取余來決定該數據存放在哪個桶中,因此每個桶都是整體數據的隨機抽樣。

        在map-side關聯操作中,兩個表如果根據相同的字段進行分桶,在處理左表的bucket是,可以直接從外表對應的bucket中提取數據進行關聯操作。map-side關聯的兩個表不一定需要完全相同的bucket數量,只要成倍數即可。同樣,Hive不會對數據是否滿足表定義中的分桶進行校驗,只有在查詢時出現異常才會報錯,所以一般,我們將分桶的工作交給Hive自己來完成(設置hive.enforce.bucketing=true).

        載入數據:

        在載入數據的時候,需要注意一下,如果說我們只是單純的使用load語句進行將數據載入到表中的話,其實是沒有任何的分桶效果的,因為這樣hdfs文件只有一個,像這樣:

hive> load data inpath '/hadoop/guozy/data/user.txt' into table user_bucket;

        此時,我們需要借助一個中間表,先將數據load到中間表中,然后通過insert的方式來向分桶表中載入數據:

hive> create table tmp_table (id int comment 'ID',name string comment '名字',age int comment '年齡') comment '測試分桶中間表' ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' ;
hive> load data inpath '/hadoop/guoxb/data/user.txt' into table tmp_table;
hive> insert into user_bucket select * from tmp_table;

        這樣就實現了分桶的效果,注意,分桶和分區的區別,分區體現在hdfs上的文件目錄,而分桶則提現在hdfs是具體的文件,上述的語句中,最終會在hdfs上生成四個文件,而不是四個目錄,如果當在次向該分桶表中insert數據后,會又增加4個文件,而不是在原來的文件上進行追加。

        一般情況下,建表分桶表的時候,我們都需要指定一下排序字段,這樣有一個好處就是,在每個桶進行連接查詢時,就變成了高效的歸並排序了。

              


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM