Hive SQL之分區表與分桶表

  Hive sql是Hive 用戶使用Hive的主要工具。Hive SQL是相似於ANSI SQL標準的SQL語言,可是二者有不徹底相同。Hive SQL和Mysql的SQL方言最爲接近,可是二者之間也存在着顯著的差別,好比Hive不支持行級數據的插入、更新和刪除,也不支持事務操做。java

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

Hive的相關概念

  • Hive數據庫

     Hive中的數據庫從本質上來講僅僅就是一個目錄或者命名空間,可是對於具備不少用戶和組的集羣來講,這個概念很是有用。首先,這樣能夠避免表命名衝突;其次,它等同於與關係型數據庫中數據庫的概念,是一組表或者表的邏輯組,很是容易理解數據庫

  • Hive表

    Hive中的表和關係型數據庫中table概念是相似的,每一個table在Hive中都有一個相應的目錄存儲數據。若是說,你沒有指定表的數據庫,那麼Hive會經過{HIVE_HOME}/conf/hive_site.xml配置文件中的hive.metastore.warehouse.dir屬性來使用默認值(通常是/usr/hive/warehouse,也能夠根據實際狀況來進行修改該配置),全部的table都保存在這個目錄中。ide

    Hive中的表分爲兩類,分別爲內部表外部表工具

    • 內部表(managed table)

      內部表,也即Hive管理的表,Hive內部表的管理包括邏輯以及語法上的,也包含實際物理意義上的,也就是說,建立Hive內部表後,表中的數據其實是存儲在表所在的目錄內,由Hive自己來管理,什麼意思呢?也就是說,若是你想刪除表的話,那麼,連同表的物理數據,元數據等會一併刪除。舉個栗子:oop

  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/這個目錄中。注意,這裏是移動,並不是複製spa

  移動數據是很是快的,由於Hive不會對數據是否符合定義的Schema作校驗,這個工做一般在讀取的時候進行(即Schema on Read),此時咱們在執行刪除操做:code

drop table managed_table;

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

    • 外部表(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');

         這樣建立表以後的表目錄結構是這樣的:

        

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

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

        二、直接經過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;

        注意:一、必須先開啓動態分區模式爲非嚴格模式

           二、這裏在指定分區的時候,並無指定具體分區的值,而只是指定的分區的字段

           三、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個文件,而不是在原來的文件上進行追加。

        通常狀況下,建表分桶表的時候,咱們都須要指定一下排序字段,這樣有一個好處就是,在每一個桶進行鏈接查詢時,就變成了高效的歸併排序了。

相關文章
相關標籤/搜索