1. 程式人生 > >Hive原理詳解

Hive原理詳解

背景

  • 引入原因: 1. – 對存在HDFS上的檔案或HBase中的表進行查詢時,是要手工寫一堆MapReduce程式碼 2. 對於統計任務,只能由動MapReduce的程式設計師才能搞定 3. 耗時耗力,更多精力沒有有效的釋放出來
  • Hive基於一個統一的查詢分析層,通過SQL語句的方式對HDFS上的資料進行查詢、統計和分析

1.資料庫的原理

       其實通常所說的將資料儲存到資料庫,並不是真的儲存到資料庫,資料庫不過是在你和你的磁碟間弄了個軟體層,其實你的資料還是被作為源資料儲存到你本地的磁碟上了,但是隻有源資料還不夠,他還儲存了元資料(資料庫儲存結構定義資訊(庫,表,列,定義資訊)

2.什麼是Hive

  • Hive是一個SQL解析引擎,將SQL語句轉譯成MR Job,然後再Hadoop平臺上執行,達到快速開發的目的。
  • Hive中的表是純邏輯表,就只是表的定義等,即表的元資料。本質就是Hadoop的目錄/檔案,達到了元資料與資料儲存分離的目的
  • Hive本身不儲存資料,它完全依賴HDFS和MapReduce。
  • Hive的內容是讀多寫少,不支援對資料的更新
  • Hive中沒有定義專門的資料格式,由使用者指定,需要指定三個屬性: 1. 列分隔符 2. 行分隔符 3. 讀取檔案資料的方法

3.HQL與傳統SQL的區別

HQL SQL
資料儲存 HDFS(源資料)、MySql或者Derby(元資料) local FS
資料格式 使用者自定義 系統決定
資料更新 不支援 支援
索引
執行 MapReduce Executor
資料規模
資料檢查 讀時模式 寫時模式

什麼是讀時模式?        很少情況下往hive中載入的資料是比較規整的,欄位與欄位之間都是分割好的,每一個欄位都不是髒資料,並且每一個欄位都是有意義的。 但是在真實場景中不見得這個盡人意,當你把不符合某個表規範的髒資料插入到這個表中,不會出錯,但是當你讀這個表的時候,髒資料讀出的是NULL。

4. Hive的原理

4.1 Hive簡介

        hive是基於Hadoop的一個數據倉庫工具,可以將結構化的資料檔案對映為一張資料庫表,並提供sql查詢功能,可以將sql語句轉換為MapReduce任務進行執行。 其優點是學習成本低,可以通過類SQL語句快速實現簡單的MapReduce統計,不必開發專門的MapReduce應用,十分適合資料倉庫的統計分析。其本質還是在HDFS上執行MapReduce,雖然簡化了操作,但是執行效率會相對減弱。         Hive資料倉庫中包含著直譯器、編譯器、優化器等,這些是其獨有的部分,用於將sql語句變成MapReduce去執行,後續的工作就自動交給了Hadoop、Yarn和MapReduce,Hive在執行時,實際的源資料存在與HFDS上,而描述資料的元資料存放在關係型資料庫中。         有人說hive既能儲存也能計算,這句話也對也不對,因為hive只是通過直譯器、編譯器、優化器來把SQL變為MR

,它的儲存也是交給了HDFS的

  1. Hive資料倉庫完成解析SQL、優化SQL、策略選擇、模型消耗;客戶端將sql語句交給Hive,Hive負責值使相對應的MapReduce執行。
  2. 存在於關係型資料庫中的元資料包含著行的分隔符、欄位的分隔符、欄位的型別、欄位的名稱等資訊。

5.Hive體系架構

5.1 Hive的基本組成

使用者介面主要有三個:CLI,Client 和 WUI。 元資料儲存:通常是儲存在關係資料庫如 mysql , derby中。 語句轉換:直譯器、編譯器、優化器、執行器。

在這裡插入圖片描述

5.2 各元件的基本功能

        使用者介面主要由三個:CLI、JDBC/Beeline和WebGUI。其中,CLI為shell命令列;JDBC/Beeline是Hive的JAVA實現,與傳統資料庫JDBC類似;WebGUI是通過瀏覽器訪問Hive。 元資料儲存:Hive 將元資料儲存在資料庫中(MySql或者Derby)。Hive中的元資料包括表的名字,表的列和分割槽及其屬性,表的屬性(是否為外部表等),表的資料所在目錄等。 直譯器、編譯器、優化器完成 HQL 查詢語句從詞法分析、語法分析、編譯、優化以及查詢計劃的生成。生成的查詢計劃儲存在HDFS 中,並在隨後有 MapReduce 呼叫執行。

5.3 Hive和Hadoop的關係

Hive和Hadoop的關係

5.4 Hive的資料管理

  • hive的表本質就是Hadoop的目錄/檔案,由配置檔案設定目錄。 -hive預設表存放路徑一般都是在你工作目錄的hive目錄裡面,按表名做資料夾分開,如果你有分割槽表的話,分割槽值是子資料夾,可以直接在其它的M/R job裡直接應用這部分資料
  1. Hive中所有的資料都儲存在 HDFS 中,沒有專門的資料儲存格式
  2. 只需要在建立表的時候告訴 Hive 資料中的列分隔符和行分隔符,Hive 就可以解析資料。

5.4.1 Hive中的內部表和外部表

  • Hive的create建立表的時候,選擇的建立方式:
  1. create table(內部)
建表:
				CREATE TABLE zxjtb1(
				id INT,
				name STRING,
  				age INT,
  				gfs ARRAY<STRING>,
  				address MAP<STRING,STRING>,
			    info STRUCT<country:String,province:String,shi:String>
				)
					ROW FORMAT DELIMITED 				  -- 行格式分割
					FIELDS TERMINATED BY ' '      		  -- 欄位的分割符
					COLLECTION ITEMS TERMINATED BY ','    -- 集合元素間的分割符
					MAP KEYS TERMINATED BY ':' 			  -- Map中key-value的分隔符
 					LINES TERMINATED BY '\n';			  -- 行與行分隔符
 建立表的方式:
 				create table zxj1 like zxjtb1;         -- 只是建立表結構
 				create table zxj2 AS SELECT* from zxjtb1;--會建立相應的表結構,並且插入資料
 插入資料的方式: 
 				INSERT INTO zxjtb1 (列1, 列2,...) VALUES (值1, 值2,....);
 				load data local inpath '/root/gfs.txt' into table zxjtb1;  -- 實質上是把檔案直接上傳到HDFS
 				from zxj2 insert into table zxjtb1 select *;  			   -- 查詢其他表資料 insert 到新表中
 				
 				
  1. create external table(外部)
建表:
create external table wc_external 
  		 (word1 STRING, 
  		  word2 STRING
  		  ) 
 	    ROW FORMAT DELIMITED 
   		FIELDS TERMINATED BY ' ' 
   		location '/test/external';
建立表方式,插入資料方式和上面相同
  • 特點: - 在匯入資料到外部表,資料並沒有移動到自己的資料倉庫目錄下,也就是說外部表中的資料並不是由它自己來管理的!而表則不一樣; - 在刪除內表的時候,Hive將會把屬於表的元資料和資料全部刪掉;而刪除外部表的時候,Hive僅僅刪除外部表的元資料,HDFS資料是不會刪除的。

5.4.2 Hive中的臨時表

  • Hive的create建立臨時表:create TEMPORARY table ttabc(id Int,name String)
  • 臨時表不支援分割槽欄位和建立索引
  • 每次退出Hive指令碼時都會清空此次建立的臨時表

5.4.3 Hive中的分割槽表

  • 在 Hive 中,表中的一個 Partition 對應於表下的一個目錄,所有的 Partition 的資料都儲存在對應的目錄中
    • 例如:pvs 表中包含 ds 和 city 兩個 Partition,則
    • 對應於 ds = 20090801, ctry = US 的 HDFS 子目錄為:/wh/pvs/ds=20090801/ctry=US;
    • 對應於 ds = 20090801, ctry = CA 的 HDFS 子目錄為;/wh/pvs/ds=20090801/ctry=CA;
  • partition是輔助查詢,縮小查詢範圍,加快資料的檢索速度和對資料按照一定的規格和條件進行管理。
  • 分割槽表(防止暴力掃描全表)又分為:靜態分割槽表和動態分割槽表
建立靜態單分割槽表:
		create table day_table (
		id int,
		content string
		) 
			partitioned by (dt string)      -- 按照dt分割槽
			ROW FORMAT DELIMITED 
			FIELDS TERMINATED BY '\t' ;
建立靜態多分割槽表:
		create table day_hour_table (
		id int, 
		content string
		) 
			partitioned by (dt int,hour int)   -- 按照dt,hour分割槽
			ROW FORMAT DELIMITED 
			FIELDS TERMINATED BY '\t' ;
靜態分割槽表載入資料必須指定分割槽:
		insert into day_table partition (dt = "9-26") values(1,"anb");
		insert into day_hour_table partition(dt=9,hour=1) values(1,"a2 bc");
		load data local inpath "/root/ceshi" into table day_table partition (dt="9-27");
		load data local inpath "/root/ceshi" into table day_table partition (dt=10,hour=10);
刪除分割槽:
		ALTER TABLE day_table DROP PARTITION (dt="9-27");
		ALTER TABLE day_table DROP PARTITION (dt=10,hour=10);
查詢表的分割槽:
		SHOW PARTITIONS table_name;

建立動態分割槽表        剛才分割槽表示靜態分割槽表,一個檔案資料只能匯入到某一個分割槽中,並且分割槽是使用者指定的;這種方式不夠靈活,業務場景比較侷限;動態分割槽可以根據資料本身的特徵自動來劃分分割槽,比如我們可以指定按照資料中的年齡、性別來動態分割槽會產出3個不同的分割槽 .

建立動態分割槽表之前的操作
		開啟支援動態分割槽
		set hive.exec.dynamic.partition=true;
		set hive.exec.dynamic.partition.mode=nonstrict;

靜態分割槽與動態分割槽建立表的語句是一模一樣的
		CREATE TABLE gfstbl_dynamic(
  		id INT,
 		 name STRING,
		  gfs ARRAY<STRING>,
		  address MAP<STRING,STRING>,
		  info STRUCT<country:String,province:String,shi:String>
		)
			partitioned by (sex string,age INT)
			ROW FORMAT DELIMITED 
			FIELDS TERMINATED BY ' ' 
			COLLECTION ITEMS TERMINATED BY ','
			MAP KEYS TERMINATED BY ':' 
			LINES TERMINATED BY '\n';
動態分割槽表載入資料:(不可以使用load,它只是將資料上傳到HDFS指定目錄中,而動態分割槽是自動分割槽的)
		from gfstbl_pt
		insert into gfstbl_dynamic partition(sex,age)
		select id,name,gfs,address,info,sex,age;
檢視分割槽數:
		show partitions gfstbl_dynamic;

5.4.4 Hive中的分桶表

  • 分桶表是對資料進行雜湊取值,然後放到不同檔案中儲存。
  • Bucket主要作用: 1. join 2. 隨機抽樣
之前要開啟分桶表的支援:set hive.enforce.bucketing=true;
建立分桶表
		create table bucket_user (id int,name string)
		clustered by (id) into 4 buckets
		ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
插入資料:
		insert into table bucket_user  partition(id) select id, name from original;
抽樣:
		select * from bucket_user tablesample(bucket x out of y on id);
		y必須是table總bucket數的倍數或者因子。
		x表示從哪個bucket開始抽取。
		分桶數/y 指的是抽取幾個桶的資料。
		例如,table總bucket數為32,tablesample(bucket 3 out of 16),表示總共抽取(32/16=)2個bucket的資料,分別為第3個bucket和第(3+16=)19個bucket的資料。



分桶+分割槽表
		CREATE TABLE psnbucket_partition( id INT, name STRING, age INT) 
		PARTITIONED BY(height DOUBLE) 
		CLUSTERED BY (age) INTO 4 BUCKETS 
		ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

5.4.5 Hive中的檢視

   &nbsp 為什麼要使用檢視? 檢視中儲存的是一推複雜的SQL語句,檢視是一個懶執行,只有我們用到此檢視的時候才會執行此複雜的SQL語句;可以將這麼長的SQL(資料表)與檢視對應對映,每次查詢這個檢視就是執行了長的SQL語句。

  • 特點:
  • 不支援物化檢視(儲存在磁碟上)
  • 只能查詢,不能做載入資料操作 load data into
  • 檢視的建立,只是儲存一份元資料,查詢檢視時才執行對應的子查詢
  • view定義中若包含了ORDER BY/LIMIT語句,當查詢檢視時也進行ORDER BY/
  • 一旦建立成功,無法修改
  1. 建立檢視CREATE VIEW IF NOT EXISTS view1 AS SELECT * FROM logtbl order by age; -建立檢視的時候不會啟動MR任務
  2.  但是在查詢檢視的時候會啟動MR任務`select * from view1;`
    
  3. show tables可以檢視已經建立的檢視
  4. drop view view1 刪除檢視

5.4.6 Hive中的索引

為什麼要使用索引?

Hive的索引目的是提高Hive表指定列的查詢速度。索引就類似目錄。 沒有索引時,類似’WHERE tab1.col1 = 10’ 的查詢,Hive會載入整張表或分割槽,然後處理所有的rows, 但是如果在欄位col1上面存在索引時,那麼只會載入和處理檔案的一部分。 與其他傳統資料庫一樣,增加索引在提升查詢速度時,會消耗額外資源去建立索引表和需要更多的磁碟空間儲存索引。 他會把索引列的每個資料都建立一個目錄,說明它所在的位置。

建立索引庫,用於存放索引
		create index t2_index on table psnbucket_partition(age) 
		as 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' with deferred rebuild 
		in table t2_index_table;
		
上述是對 psnbucket_partition表的age欄位設定索引 t2_index,索引的內容放入 t2_index_table;

這一步是真正的建立索引資訊,並且儲存到索引庫中,若資料庫有新增資料,也可以使用以上語句重建索引
		alter index t2_index on psnbucket_partition rebuild; 	

5.4.7 Hive資料型別

  • 資料型別 1. TINYINT -128~127 2. SMALLINT -32,768~32767 3. INT -2,147,483,648~2147483647 4. FLOAT 5. DOUBLE 6. STRING 字串 7. VARCHAR 可變長度字串 8. CHAR 字元 9. ARRAYS 陣列型別 10. MAPS 鍵值對集合型別 11. STRUCTS 結構化型別

5.4.8 總結

索引和分割槽最大的區別就是索引不分割資料庫,分割槽分割資料庫。

索引其實就是拿額外的儲存空間換查詢時間,但分割槽已經將整個大資料庫按照分割槽列拆分成多個小資料庫了。

分割槽和分桶最大的區別就是分桶隨機分割資料庫,分割槽是非隨機分割資料庫

因為分桶是按照列的雜湊函式進行分割的,相對比較平均;而分割槽是按照列的值來進行分割的,容易造成資料傾斜。

其次兩者的另一個區別就是分桶是對應不同的檔案(細粒度),分割槽是對應不同的資料夾(粗粒度)。

注意:普通表(外部表、內部表)、分割槽表這三個都是對應HDFS上的目錄,桶表對應是目錄裡的檔案

5.5 Hive的調優

核心思想:把Hive SQL當作Map Reduce程式去優化 但是不是所有的SQL都會被轉化為MapReduce來執行

  1. select僅查詢本表字段
  2. where只對本表字段做條件過濾

5.5.1 Hive的執行方式

  • 本地模式
    • 開啟本地模式set hive.exec.mode.local.auto=true;
    • 當滿足以下條件時才會真正的使用本地模式,否則使用叢集模式(總體來說適用於少量資料時) 1. 輸入資料大小必須小於引數 2. map數必須小於引數 3. reduce數必須==0|1
  • 叢集模式

5.5.2 平行計算

  • 並行模式的開啟set hive.exec.parallel=true;
  • 一次SQL計算中所允許的最大的Map個數hive.exec.parallel.thread.number;

5.5.3 嚴格模式

  • 設定嚴格模式增加查詢的效率set hive.mapred.mode=strict;(預設是非嚴格模式)
  • 嚴格模式要求 1. 對於分割槽表,必須新增where對於分割槽欄位的條件過濾 2. order by語句必須包含limit限制 3. 限制笛卡爾積的查詢(效率太低)

5.5.4 Hive join

  • join計算時,將小表(驅動表)放在join左邊
  • Map join:在Map端完成Join
    • 實現方式:
      1. SQl方式:在SQl語句中新增Map join標記SELECT /*+ MAPJOIN(smallTable) */ smallTable.key, bigTable.value FROM smallTable JOIN bigTable ON smallTable.key = bigTable.key
      2. 開啟自動的Map joinset hive.auto.convert.join = true;

5.5.5 Map-Side聚合

  • 設定以下開啟在Map端額聚合combinerset hive.map.aggr=true;
  • 相關的配置引數 1. hive.groupby.mapaggr.checkinterval: 預設100000;map端group by執行聚合後產生的最大記錄數(預設:100000) 2. hive.map.aggr.hash.min.reduction:預設0.5 ;進行聚合的最小比例 3. hive.map.aggr.hash.percentmemory: 預設0.5 ;map端聚合使用的記憶體佔總記憶體的比例 4. hive.map.aggr.hash.force.flush.memory.threshold:預設0.9 ; 5. map端做聚合操作是hash表的最大可用內容,大於該值則會觸發flush;map端做聚合操作是hash表的最大可用內容,大於該值則會觸發flush 6. hive.groupby.skewindata;是否對GroupBy產生的資料傾斜做優化,預設為false

5.5.6 控制Hive中Map以及Reduce的數量

  • Map數量相關的引數
    1. mapred.max.split.size一個split的最大值,即每個map處理檔案的最大值
    2. mapred.min.split.size.per.node一個節點上split的最小值
    3. mapred.min.split.size.per.rack;一個機架上split的最小值
  • Reduce數量相關的引數
    1. mapred.reduce.tasks;強制指定reduce任務的數量
    2. hive.exec.reducers.bytes.per.reducer 預設 256M;每個reduce任務處理的資料量
    3. hive.exec.reducers.max 預設1009;每個任務最大的reduce數

5.5.7 Hive-JVM重用

  • 適用場景:
    1. 小檔案個數過多
    2. task個數過多
  • 通過set mapred.job.reuse.jvm.num.tasks=n;來設定,n為task插槽個數

5.5.8 Hive優化—資料傾斜

  • 操作
    • Join
    • Group by
    • Count Distinct
  • 原因
    • key分佈不均導致的
    • 人為的建表疏忽
    • 業務資料特點
  • 症狀
    • 任務進度長時間維持在99%(或100%),檢視任務監控頁面,發現只有少量(1個或幾個)reduce子任務未完成。
    • 檢視未完成的子任務,可以看到本地讀寫資料量積累非常大,通常超過10GB可以認定為發生資料傾斜。
  • 傾斜度
    • 平均記錄數超過50w且最大記錄數是超過平均記錄數的4倍。
    • 最長時長比平均時長超過4分鐘,且最大時長超過平均時長的2倍。
  • 萬能方法
    • hive.groupby.skewindata=true

6. Hive環境搭建和部署