1. 程式人生 > >Hive表操作及管理

Hive表操作及管理

Hive是基於Hadoop的一個數據倉庫工具,可以將結構化的資料檔案對映為一張資料庫表,並提供簡單的sql查詢功能,可以將sql語句轉換為MapReduce任務進行執行。 其優點是學習成本低,可以通過類SQL語句快速實現簡單的MapReduce統計,不必開發專門的MapReduce應用,十分適合資料倉庫的統計分析。但缺點也非常明顯。因為Hive運算引擎來自MapReduce,MapReduce中間結果都儲存在磁碟,IO導致速度很慢,這也是Hive最顯著的缺點。

作為對元資料SQL化操作的引擎,Hive同樣使用RDBMS的資料表物件管理資料。

一、Hive表

Hive中能存在兩種表:

  • 內部表(managed table),資料檔案、統計檔案、元資料都由Hive自己管理,換句話說,這個表資料儲存在哪裡我們不用關心,也不用提供,Hive預設儲存在HDFS。Hive能管理原始資料的整個生命週期。Hive表刪除後,資料也隨之刪除。
  • 外部表(external table),資料檔案儲存在其他系統中,可能是HDFS,也可能是HBase、ASV等,HIve只保留對映關係,但Hive表刪除後,資料不會丟失,仍然存在於其他系統中。

二、建立表

由於Hive支援標準的SQL(包括SQL:2003和SQL:2011標準的一些特性),建立表與後面提到的CURD都比較好理解。以下是一些簡單的建立表語句例子:

簡單的內部表

create table tb (id int, name String, age int);  

分割槽的內部表

create table ez_part_test (  
    id int,   
    col1 string,   
    col2 string) partitioned by   
  (type int) stored as orc  

外部表(HDFS)
create external table example_csv_tb (  
    id int,  
    col1 string,  
    col2 string) ROW FORMAT   
  delimited fields terminated by ','   
  lines terminated by '\n'  
  stored as textfile location "/ez/example"  

HiveSQL不僅僅定義欄位及相應的型別,也提供定義欄位屬性、表儲存格式等的語義。

1、外部表

例如,在HDFS上有個在 hdfs://myhost:8020/ez/example/lang.csv

的資料檔案,內容如下:

1,java,20  
2,c,40  
3,Golang,8  
4,Perl,35  
5,PHP,20  


這時候需要一個Hive表,對映到這個檔案,方便用SQL查詢,這個表既是外部表。同理對映到HBase表也是外部表。於是我們使用如下語句:
create external table lang (  
    id int,  
    name string,  
    field1 int) ROW FORMAT  
  delimited   
    fields terminated by ','  
    lines terminated by '\n'  
  stored as textfile   
  location "/ez/example/lang.csv"  

檔案第一列是數字,我們定義為id列,第二列定義為name,第三列隨便指定個名字為field。列與列間用逗號隔開。一行記錄結束用換行符 ‘\n’結尾。於是後面的ROW FORMAT row_format子句定義整個格式行為,如下:
row_format  
  : DELIMITED [FIELDS TERMINATED BY char [ESCAPED BY char]]  
    [COLLECTION ITEMS TERMINATED BY char]  
    [MAP KEYS TERMINATED BY char]  
    [LINES TERMINATED BY char]  
    [NULL DEFINED AS char]   -- (Note: Available in Hive 0.13 and later)  
  | SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]  

必須定義的兩個屬性之一,其一是DELIMITED,其二是SERDE。第一個用於描述文字檔案,第二個用於描述二進位制檔案(序列化與反序列化)。我們只涉及到描述文字檔案。於是描述欄位間的分割符號為',',行結束符為'\n'。

stored as file_format宣告儲存的檔案為什麼格式。
file_format:  
  : SEQUENCEFILE  
  | TEXTFILE    -- (Default, depending on hive.default.fileformat configuration)  
  | RCFILE      -- (Note: Available in Hive 0.6.0 and later)  
  | ORC         -- (Note: Available in Hive 0.11.0 and later)  
  | PARQUET     -- (Note: Available in Hive 0.13.0 and later)  
  | AVRO        -- (Note: Available in Hive 0.14.0 and later)  
  | INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname  

這裡我們配置TEXTFILE(文字檔案),也是預設的Hive外部表儲存格式。

location hdfs_path子句意思很明顯了,資料檔案儲存的位置,注:必須是HDFS檔案路徑。
至此一個最簡單的外部表就建立完成了。可以直接使用如下語句查詢試試:
select * from lang;  

注意:這裡我們沒有指定資料庫,所以這個表將建立在default資料庫中,Hive預設內建的一個數據庫。

2、內部表
例如,我們沒有資料檔案,只是想建立一個Hive表,這個Hive表以後用於儲存資料用,或從其他資料來源匯入,或程式寫入等。內部表看起來就像RDBMS的資料表,Hive有足夠大的許可權可以操縱表裡的資料,包括刪除。
建立外部表時,使用的語句是create external table。而預設情況下,不使用external則是預設建立內部表。

以下是建立表語法:
    CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name    -- (Note: TEMPORARY available in Hive 0.14.0 and later)  
      [(col_name data_type [COMMENT col_comment], ... [constraint_specification])]  
      [COMMENT table_comment]  
      [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]  
      [CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]  
      [SKEWED BY (col_name, col_name, ...)                  -- (Note: Available in Hive 0.10.0 and later)]  
         ON ((col_value, col_value, ...), (col_value, col_value, ...), ...)  
         [STORED AS DIRECTORIES]  
      [  
       [ROW FORMAT row_format]   
       [STORED AS file_format]  
         | STORED BY 'storage.handler.class.name' [WITH SERDEPROPERTIES (...)]  -- (Note: Available in Hive 0.6.0 and later)  
      ]  
      [LOCATION hdfs_path]  
      [TBLPROPERTIES (property_name=property_value, ...)]   -- (Note: Available in Hive 0.6.0 and later)  
      [AS select_statement];   -- (Note: Available in Hive 0.5.0 and later; not supported for external tables)  
       
    CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name  
      LIKE existing_table_or_view_name  
      [LOCATION hdfs_path];  
       
    data_type  
      : primitive_type  
      | array_type  
      | map_type  
      | struct_type  
      | union_type  -- (Note: Available in Hive 0.7.0 and later)  
       
    primitive_type  
      : TINYINT  
      | SMALLINT  
      | INT  
      | BIGINT  
      | BOOLEAN  
      | FLOAT  
      | DOUBLE  
      | DOUBLE PRECISION -- (Note: Available in Hive 2.2.0 and later)  
      | STRING  
      | BINARY      -- (Note: Available in Hive 0.8.0 and later)  
      | TIMESTAMP   -- (Note: Available in Hive 0.8.0 and later)  
      | DECIMAL     -- (Note: Available in Hive 0.11.0 and later)  
      | DECIMAL(precision, scale)  -- (Note: Available in Hive 0.13.0 and later)  
      | DATE        -- (Note: Available in Hive 0.12.0 and later)  
      | VARCHAR     -- (Note: Available in Hive 0.12.0 and later)  
      | CHAR        -- (Note: Available in Hive 0.13.0 and later)  
       
    array_type  
      : ARRAY < data_type >  
       
    map_type  
      : MAP < primitive_type, data_type >  
       
    struct_type  
      : STRUCT < col_name : data_type [COMMENT col_comment], ...>  
       
    union_type  
       : UNIONTYPE < data_type, data_type, ... >  -- (Note: Available in Hive 0.7.0 and later)  
       
    row_format  
      : DELIMITED [FIELDS TERMINATED BY char [ESCAPED BY char]] [COLLECTION ITEMS TERMINATED BY char]  
            [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]  
            [NULL DEFINED AS char]   -- (Note: Available in Hive 0.13 and later)  
      | SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]  
       
    file_format:  
      : SEQUENCEFILE  
      | TEXTFILE    -- (Default, depending on hive.default.fileformat configuration)  
      | RCFILE      -- (Note: Available in Hive 0.6.0 and later)  
      | ORC         -- (Note: Available in Hive 0.11.0 and later)  
      | PARQUET     -- (Note: Available in Hive 0.13.0 and later)  
      | AVRO        -- (Note: Available in Hive 0.14.0 and later)  
      | INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname  
       
    constraint_specification:  
      : [, PRIMARY KEY (col_name, ...) DISABLE NOVALIDATE ]  
        [, CONSTRAINT constraint_name FOREIGN KEY (col_name, ...) REFERENCES table_name(col_name, ...) DISABLE NOVALIDATE  

三、建立分割槽表

目前我只嘗試過在內部表上分割槽,沒有嘗試過外部表分割槽。分割槽是將HDFS中不同分割槽的資料檔案存放於不同的目錄下。例如一個Hive內部表資料保存於HDFS中/user/hive/warehouse/mytest.db/下,這個目錄下全是資料檔案(可能是文字檔案格式,也可能是其他格式,根據file_format指定)。這時候若引入一個欄位用於分割槽,則將會在這個目錄下產生新的目錄,每個目錄對應一個分割槽。每個分割槽資料分別存在自己對應的目錄下。這樣查詢效率也會更高。

建立分割槽表將使用到partitioned by子句。如下分割槽表:

create table partition_tb (  
id int, col1 string, col2 string)  
partitioned by (type int)  
stored as ORC  

這裡需要注意,當指定分割槽列時,分割槽列不能是資料列。上面type列就沒有出現在資料列(id,col1,col2)中。而在查詢和寫入語句中,type列完全可以像普通資料列一樣使用,放在where子句,放在select列中。

當表建立好後,只是聲明瞭有一個叫type的列可以用於分隔資料,但沒有建立分割槽出來,也就是說,現在HDFS目錄下還沒有分割槽目錄,分割槽資訊的元資料也沒有形成。那我們是等資料寫入時再檢測是否分割槽存在,並建立與否,還是事先建立好所有的分割槽,靜等資料進入呢?這個也是Hive靜態分割槽與動態分割槽的問題。我們完全可以配置使Hive允許動態分割槽。這裡我只記錄了非動態分割槽的做法(後續學習了動態分割槽留待補充)。配置引數hive.exec.dynamic.partition.mode=nonstrict

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


結合上面的partition_tb表,我們建立一個分割槽:
alter table partition_tb add partition (type = 1)  
注意:這裡也可以指定LOCATION子句,這樣分割槽目錄將建立到LOCATION下。但之前的資料將還存在這個表中。

為表做分割槽主要考慮的是效率問題,重點需要考慮分割槽的列的基數(也就是該列包含唯一值的個數)。選擇基數很高的列來做分割槽會導致資料嚴重的碎片化。不要對資料過分的分割槽。如果有太多的小分割槽,那麼對這麼多的分割槽目錄進行掃描代價也是比較高的,甚至可能比全表掃描還高。


四、刪除表

上面已經提到,對於內部表,刪除後hive也會刪除HDFS上儲存的資料。對於外部表,只是表的元資料(metastore)會刪除,真實資料並不會刪除。

DROP TABLE [IF EXISTS] table_name [PURGE];     -- (Note: PURGE available in Hive 0.14.0 and later)  

下一篇將記錄表操作CURD及筆者倒騰Hive遇到的一些坑。