1、Hive出現背景
Hive是Facebook開發並貢獻給Hadoop開源社區的。它是建立在Hadoop體系架構上的一層SQL抽象,使得數據相關人員使用他們最為熟悉的SQL語言就可以進行海量數據的處理、分析和統計工作,
而不是必須掌握Java等編程語言和具備開發MapReduce程序的能力。Hive SQL實際上先被SQL解析器進行解析然后被Hive框架解析成一個MapReduce可執行計划,並按照該計划生成MapReduce任務后交給Hadoop集群處理。
由於Hive SQL是翻譯為MapReduce任務后在Hadoop集群執行的,而Hadoop是一個批處理系統,所以Hive SQL是高延遲的,不但翻譯成的MapReduce任務執行延遲高,任務提交和處理過程也會消耗時間,因此即使Hive處理
的數據集非常小(比如即MB,幾十MB),在執行時也會出現延遲現象。這樣Hive的性能就不能很好地和傳統的Oracle數據庫、MySQL數據庫進行比較。Hive不能提供數據排序和查詢緩存功能,也不提供在線事務處理、更不提供
實時的查詢和記錄級的更新,但它能很好的處理不變的大規模數據集,當然這是 和其根植於Hadoop近似線性的可擴展性分不開的。
2、Hive基本架構
作為基於Hadoop的主要數據倉庫解決方案,Hive SQL是主要的交互接口,實際的數據保存在HDFS文件中,真正的計算和執行則由MapReduce完成。而它們之間的橋梁是Hive引擎。下面是架構圖:

Hive組件包括UI組件、Driver組件(Complier,Optimizer和Executor)、Metastore組件、CLI(Command Line Interface, 命令行接口)、JDBC/ODBC、Thrift Server和Hive Web Interface(HWI)等。
Driver組件:核心組件,整個Hive的核心,該組件包括Complier(編譯)、Optimizer(優化器)和Executor(執行器),它們的作用是對Hive SQL語句進行解析、編譯優化,生成執行計划,然后調用底層的MapReduce計算框架。
Metastore組件:元數據服務組件,這個組件存儲Hive的元數據。Hive的元數據存儲在關系數據庫里,Hive支持的關系數據庫有Derby和MySQL。默認情況下,Hive元數據保存在內嵌的Derby數據庫中,只能允許一個會話鏈接,
只適合簡單的測試。實際生產中不適用,為了支持多用戶會話,需要一個獨立的元數據庫(如MySQL),Hive內部對MySQL提供了很好的支持。
CLI:命令行接口。
Thrift Server:提供JDBC和ODBC接入的能力,用來進行可擴展且跨語言 的服務開發。Hive集成了該服務,能讓不同的編程 語言調用Hive的接口。
Hive Web Interface(HWI):Hive客戶端提供了一個通過網頁方式訪問Hive所提供的服務,這個接口對應Hive的HWI組件。
Hive通過CLI、JDBC/ODBC,或者HWI接收相關的Hive SQL查詢,並通過Driver組件進行編譯、分析優化,最后變成可執行的MapReduce。Hive主要組件執行過程如下圖:

3、Hive SQL
Hive SQL是Hive用戶使用Hive的主要工具。Hive SQL是類似於ANSI SQL標准的SQL語言,但兩者又不完全相同。Hive SQL和MySQL的SQL方言最為接近,但兩者之前也存在顯著差異,比如Hive不支持行級數據插入、
更新和刪除,也不支持事務等。
3.1、Hive關鍵概念
3.1.1、Hive數據庫
Hive中的數據庫從本質上來說僅僅是一個目錄或命名空間,但是對於具有很多用戶和組的集群來說,這個概念非常有用。首先,這樣可以避免表命名沖突;其次,它等同於數據型數據庫在的數據庫概念呢,是一組表或表
的邏輯組,非常容易理解。
3.1.2、Hive表
Hive中的表(Table)和關系數據庫中的table在概念上是類似的,每個table在Hive在都有一個對應的目錄存儲數據,如果么有指定表的數據庫,那么HIve會通過{HIVE_HOME}/conf/hive-site.xml配置文件中的hive.metastore.
warehouse.dir屬性來使用默認值(一般是 /user/hive/warehouse, 也可以根據實際的情況來修改這個配置),所有的table數據(不包括外部表)都保存在這個目錄。
Hive分為兩類,即內部表和外部表。所謂內部表(managed table)即Hive管理的表,Hive內部表的管理既包含邏輯以及語法上的,也包含實際物理意義上的,即創建Hive內部表時,數據將真實存在於表所在的目錄內,刪除
內部表時,物理數據和文件也一並刪除。外部表(external table )則不然,其管理僅僅是在邏輯和語法意義上的,即新建表僅僅是指向一個外部目錄而已。同樣,刪除時也不物理刪除外部目錄,而僅僅是將引用和定義刪除。
考慮下面的語句:
CREATE TABLE my_managed_table(col1 STRING);
LOAD DATA INPATH '/user/root/data.txt' INTO table my_managed_table
上述語句會將hdfs:// user/root/data.txt 移動到Hive的對應目錄hdfs://user/hive/warehouse/my_managed_table,但是載入數據的速度非常快,因為Hive只是把數據移動到對應的目錄,不會對數據是否符合定義的Schema做校驗,
這個工作通常在讀取時候進行(即為Schema On Read)。
同時,my_managed_table使用DROP語句刪除后,其數據和表的元數據被刪除,不再存在,這就是 Hive managed的意思:
DROP TABLE my_managed_table;
外部表則不一樣,數據的創建和刪除完全由自己控制,Hive不管理這些數據,數據的位置在創建時指定:
CREATE EXTERNAL TABLE external_table(dummy STRING)
LOCATION '/user/root/external_table';
LOAD DATA INPATH '/user/root/data.txt' INTO TABLE exteranl_table;
指定EXTERNAL關鍵字后,Hive不會把數據移動warehouse目錄中。事實上,Hive甚至不會校驗外部表的目錄是否存在。這使得我們可以在創建表之后再創建數據,當刪除外部表時,Hive只刪除元數據,而不會刪除外部實際
物理文件。
選擇內部表還是外部表?在大多數情況下,這兩者的區別不是很明顯。如果數據的所有處理都在Hive中進行,那么更傾向於選擇內部表。但是如果Hive和其它工具針對相同的數據集做處理,那么外部表更合適。一種常見的模式
是使用外部表訪問存儲的HDFS(通常由其它工具創建)中 的初始數據,然后使用Hive轉換數據並將其結果放在內部表中,相反,外部表也可以用於將Hive的處理結果導出供其它應用使用。使用外部表另一種場景是針對一個數據集,
關聯多個Schema。
3.1.3、分區和桶
Hive 將表划分為分區(partition),partition根據分區字段進行。分區可以讓數據的部分查詢變得更快。表或者分區可以進一步被划分為桶(bucket)。桶通常在原始數據中加入一些額外的結構,這些結構可以用於高效查詢。
例如,基於用戶ID的分桶可以使用基於用戶的查詢非常快。
分區:
假設日志數據中,每條記錄都帶有時間戳。如果根據時間來分區,那么同一天的數據將被划分到同一個分區中。針對某一天或某幾天數據的查詢將會變得很高效,因為只需要掃描對應分區的文件。分區並不會導致跨度的的查詢
變得低效。
分區可以通過多個維度來進行。例如,通過日期划分后,還可以根據國家進一步划分。
分區在創建表的時候使用PARTITIONED BY從句定義,該從句接收一個字段列表:
CREATE TABLE logs (ts BIGINT, line STRING) PARTITIONED BY (dt STRING, country STRING);
當導入數據到分區表時,分區的值被顯式指定:
LOAD DATA INPATH '/user/root/path'
INTO TABLE logs
PATITION(dt='2001-01-01', country='GB');
文件系統上,分區作為表目錄的下一級目錄存在,如下圖:

在實際的SQL中,靈活指定分區將大大提高其效率,如下代碼將僅會掃描2001-01-01目錄下的GB目錄:
select ts, dt, line from logs where dt = '2001-01-01' and country='GB'
分桶:
在表或者分區中使用桶通常由兩個原因:
一個是為了高效查詢。桶在表中加了特殊的結構,Hive在查詢的時候可以利用這些結構提高效率。例如,如果兩個表根據相同的字段進行分桶,則在對這兩個表進行關聯的時候,可以
使用map-side關聯高效實現,前提是關聯的字段在分桶中出現。
二是可以高效地進行抽樣。在分析大數據集時,經常需要對部分抽樣數據進行觀察和分析,分桶有利於高效實現抽象。
為了讓Hive對表進行分桶,通過CLUSTERED BY 從句在創建表的時候指定:
CREATE TABLE bucketed_users(id INT, name STRING)
CLUSTERED BY (id) INTO 4 BUCKETS;
指定表根據id字段進行分桶,並且分為4個桶。分桶時,Hive根據字段哈希后取余數來決定數據應該放哪個桶,因此每個桶都是整體數據的隨機抽樣。
在map-side的關聯中,兩個表根據相同的字段進行分桶,因此處理左邊表的bucket時,可以直接從外表對應的bucket中提取數據進行關聯操作。map-side關聯的兩個表不一定需要完全相同bucket數量,只要成倍數即可。
需要注意的是,Hive並不會對數據是否滿足表定義中的分桶進行校驗,只有在查詢時出現異常才會報錯。因此,一種更好的方式是將分桶的工作交給Hive來完成(設置hive.enforce.bucketing屬性為true即可)。
3.2、Hive數據庫
創建數據庫
創建數據庫的完整語法如下:
CREATE (DATABASE|SCHEMA) [IF NOT EXISTS] database_name
[COMMENT database_name]
[LOCATION hdfs_path]
[WITH DBPROPERTIES(property_name=property_value,...)];
例如:
hive> create database my_hive_test if not exists
commit 'this is my first hive database'
with dbproperties(‘creator’ ='mike', 'date' = '2018-08-10');
切換數據庫
hive> use my_hive_test;
查看數據庫
hive> describe database my_hive_test;
刪除數據庫
hive> drop database my_hive_test;
默認情況下,Hive不允許用戶刪除一個包含表的數據庫。用戶要么先刪除數據庫中的表,再刪除數據庫;要么在刪除命令的最后加上關鍵字CASCADE,這樣Hive會先刪除數據庫中的表,再刪除數據庫,
命令如下(務必謹慎使用此命令):
hive>drop database my_hive_test CASCADE;
查看所有數據庫
hive>show databases;
4、Hive函數列表

參考資料:《離線和實時大數據開發實戰》
