兩種Hive表
hive存儲:數據+元數據
托管表(內部表)
創建表:
hive> create table test2(id int,name String,tel String)
> ROW FORMAT DELIMITED
> FIELDS TERMINATED BY ',';
准備數據文件my.txt
1,scc0,20,131888888888
2,scc1,22,13222222222
3,scc2,21,183938384983
灌數據:
load data local inpath '/usr/local/src/my.txt' into table test2;
查看數據:
hive> select * from test2;
OK
1 scc0 20
2 scc1 22
3 scc2 21
Time taken: 0.132 seconds, Fetched: 3 row(s)
hdfs中的warehouse文件夾下面會多一個文件夾叫做test2。里面的文件名叫做my.txt
刪除表:
hive> drop table test2;
OK
Time taken: 0.43 seconds
warehouse文件夾下的test2以及里面的所有文件被刪除。內部表刪除會同時刪除元數據和數據文件。在建表的時候可以指定location,創建的內部表默認是存在warehouse/[tablename]
,也可以指定目錄存放。
create table test2(id int,name String,tel String) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' location '/scc/tmpdir';
外部表
創建表:
多加一個關鍵詞external
create table test3(id int,name String,tel String) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
也可以指定location。默認還是放在warehouse/[tablename]
灌數據方式同上。
查看方式同上。
刪除命令同上:
刪除后查詢:
hive> show tables;
OK
haha
Time taken: 0.034 seconds, Fetched: 1 row(s)
表中已經不再存在test3, 但是HDFS中的目錄以及文件均存在。說明外部表在刪除的時候僅僅刪除了元數據,並未刪除存儲文件。
分區和桶
表大於分區大於桶
參考此鏈接
1. 先說分區
在HDFS中,分區的表現為表的子目錄。
在創建分區的命令上,分區表現為指定分區partitioned by (partitio-name string)
在查詢方式上,分區就相當於表的字段。
創建帶分區(以時間time
為分區)的表:
create table tbhaspar(id int,name string,tel string) partitioned by(time string) row format delimited fields terminated by ',';
准備數據:
(下面數據中不含time字段,也可以帶有time字段,如果按照下面灌數據的方式,帶有的time字段的數據會被分區名覆蓋掉)
1,scc0,131888888888
2,scc1,13222222222
3,scc2,183938384983
4,scc3,16222232222
5,scc4,17222222222
灌數據:
load data local inpath '/usr/local/src/my.txt' into table tbhaspar partition (time='03-01');
load data local inpath '/usr/local/src/my.txt' into table tbhaspar partition (time='03-02');
load data local inpath '/usr/local/src/my.txt' into table tbhaspar partition (time='03-03');
查詢
(創建表的時候指定了3個字段1個分區,接下來的查詢結果就好像是看到了4個字段):
hive> select * from tbhaspar;
OK
1 scc0 131888888888 03-01
2 scc1 13222222222 03-01
3 scc2 183938384983 03-01
4 scc3 16222232222 03-01
5 scc4 17222222222 03-01
1 scc0 131888888888 03-02
2 scc1 13222222222 03-02
3 scc2 183938384983 03-02
4 scc3 16222232222 03-02
5 scc4 17222222222 03-02
1 scc0 131888888888 03-03
2 scc1 13222222222 03-03
3 scc2 183938384983 03-03
4 scc3 16222232222 03-03
5 scc4 17222222222 03-03
Time taken: 0.081 seconds, Fetched: 15 row(s)
查看表信息:
hive> describe tbhaspar;
OK
id int
name string
tel string
time string
# Partition Information
# col_name data_type comment
time string
Time taken: 0.09 seconds, Fetched: 9 row(s)
指定分區查詢
(下面的查詢方式,好像分區真的是一個字段):
select * from tbhaspar where time = '03-01';
對,上面說的都是
靜態分區
,下面看看動態分區。
動態分區
可以根據查詢得到的數據動態分配到分區里。其實動態分區與靜態分區區別就是不指定分區目錄,由系統自己選擇。
該功能需要手動開啟:
hive> set hive.exec.dynamic.partition=true;
- 創建一個跟剛才一樣的分區表id,name,tel partition=time
- 灌數據。灌數據的方式只能通過從別的表查詢得到,不能直接從local文件加載。我們下面從剛才的靜態分區表進行加載(當然我們此時把分區表當成未分區表來用,現實中都是先把數據加載到普通表,然后再讀取並加載到動態分區中)。
hive> insert overwrite table tbhasdypar partition(time) select * from tbhaspar;
執行完就開始調MR了。。等一會兒看結果!直接就分區了!很帥!

2. 再說桶
桶是更細粒度的數據范圍划分。桶的作用體現之一:MR階段可以大大減少Join操作(別人這么說的,我不知道)。
Hive采用對列值哈希,然后除以桶的個數求余的方式決定該條記錄存放在哪個桶當中。
建一個帶桶的表
按照id分成3個桶。
hive> create table buck2 (id int,name string) clustered by (id) sorted by(id) into 3 buckets row format delimited fields terminated by ',' stored as textfile;
灌數據
先看一眼我們要灌的數據

hive> insert overwrite table buck2 select id,name from tbhaspar;
看結果
看結果之前,先設置一下這個:
set mapreduce.job.reduces=4;
為什么?因為分區的效果就是在MapReduce中體現出來的。我們設置多個Reduce觀察一下排序結果。

HDFS的buck2下面多了三個文件夾,對應值hash得到的三種余數。
執行:
hive> select * from buck2 ;
下圖結果中,正好是三個桶,而且是hash分桶,很明顯。

上面是一個無序結果。下面的命令可以查看有序的結果。會在每個reduce里面排序。
hive> select * from buck2 sort by id ;
Hive避免MapReduce
把這個屬性設置為true
hive.exec.mode.local.auto=true
hive在運行的時候嘗試先使用本地模式運行 否則幾乎所有的操作都會觸發MR
分區查詢-strict嚴格模式
hive.mapred.mode=strict
上述參數 嚴格模式下 如果針對分區表的查詢,where子句沒有添加分區過濾的話,任務禁止提交。
hive.mapred.mode=nonstrict
上述參數 取消嚴格模式
Hive數據傾斜問題 以及解決思路
MR階段,Map產生的數據是根據Hash算法生成的key,按key選擇合適的reduce,會因為數據特殊性引起的key聚集,造成某些Reduce任務繁重,某些reduce幾乎沒有任務。
配置參數:
hive.map.aggr=true//Map 端部分聚合,相當於Combiner
hive.groupby.skewindata=true
原理就是:將數據隨機分成兩個Job,第一個job隨機分到不同的reduce,很有可能出現相同的key在不同的reduce里面。第二個Job可以根據預處理的反饋,將key分配到對應的reduce中,基本上同一個key都在一個reduce里面。整體上可以減少數據處理時間,做到負載均衡。
SQL調節:
- 如果兩個表都是大表,那么可以對key較少的那部分,可以賦一個隨機的key,值為null。傾斜的數據可以分配到不同的reduce上,null值也不會影響最后的結果計算。
- 如果表一大一小(約定1000條記錄一下),內存加載較小的表在map端完成redcue操作。
還有其他方法,沒使用過,略去不表。
Hive中的order by,sort by,distribute by, cluster by作用以及用法
- order by:在查詢的時候sql指定,進行全局排序。不管會有多少個map節點,只會在一個reduce節點內進行處理,所以會很慢。並且,如果手動設置了嚴格模式,還是必須要指定limit條數的,因為數據量非常大,可能不會出結果。
- sort by:原理類似於歸並排序。在每個reduce節點進行排序,做到局部有序,最后進行全局排序的時候就可以提升不少的效率。
- distribute by:都是和sort by 一起使用,並且先於它。作用是將指定的字段值相同的,分配到同一個reduce進行處理。參考這個鏈接- distribute by和sort by一起使用
- cluster by:是2,3的合並
cluster by id等價於distibute by id sort by id
和3中語句等價的語句:
select mid, money, name from store cluster by mid sort by money
Hive文件存儲、壓縮格式
- text file
默認設置。建表時會把數據文件拷貝到hdfs上不進行處理。 - sequence file
二進制存儲。分割,壓縮比較方便。使用<key,value>存儲,key是空的。
三種壓縮可選,None,Record,Block。Record效率低一些,一般用Block - rc file行列存儲 不好用
- orc file 3的升級版。性能很好,存儲效率比text file節省很多。
從本地加載數據只用用text file格式。然后才可以通過text file轉換成2,3,4的格式。
text file文件可以直接通過cat 查看。而2,3,4的源文件無法直接查看,只能借助表查詢才能查看其中的內容。
=====================
我的其他相關文章: