目錄
- 1 hive的介紹
- 2 hive的架構
- 3 Hive 資料模型
- 4 常用操作
- 4.1 資料庫相關
- 4.2 內部表外部表
- 4.3 創建磁區表
- 4.4 增刪磁區
- 4.5 hive中的join
- 4.6 json決議
- 5 常用函式
- 5.1 數值函式
- 5.2 日期函式
- 5.3 條件函式
- 5.4 字串函式
- 5.5 型別轉換
- 6 hive常用的優化
- 6.1 Fetch抓取(Hive可以避免進行MapReduce)
- 6.2 本地模式
- 6.3 磁區表分桶表
- 6.4 join優化
- 6.4.1 小表Join大表
- 6.4.2 mapjoin
- 6.5 group by
- 6.6 Map數
- 6.7 reduce數
- 6.8 jvm重用
- 6.9 資料壓縮與存盤格式
- 1.壓縮方式
- 2.存盤格式
- 6.10 并行執行
- 6.11 合并小檔案
- 7 hive的資料傾斜
1 hive的介紹

? Hive是基于Hadoop的一個資料倉庫工具,可以將結構化的資料檔案映射為一張資料庫表,并提供類SQL查詢功能,
? 本質是將SQL轉換為MapReduce程式,
? 主要用途:用來做離線資料分析,比直接用MapReduce開發效率更高,
2 hive的架構

用戶介面:包括 CLI JDBC/ODBC WebGUI,其中,CLI(command line interface)為shell命令列;JDBC/ODBC是Hive的JAVA實作,與傳統資料庫JDBC類似;WebGUI是通過瀏覽器訪問Hive,
元資料存盤:通常是存盤在關系資料庫如 mysql/derby中,Hive 將元資料存盤在資料庫中,Hive 中的元資料包括表的名字,表的列和磁區及其屬性,表的屬性(是否為外部表等),表的資料所在目錄等,
解釋器 編譯器 優化器 執行器:完成 HQL 查詢陳述句從詞法分析 語法分析 編譯 優化以及查詢計劃的生成,生成的查詢計劃存盤在 HDFS 中,并在隨后有 MapReduce 呼叫執行,
3 Hive 資料模型
Hive中所有的資料都存盤在HDFS中,沒有專門的資料存盤格式
在創建表時指定資料中的分隔符,Hive 就可以映射成功,決議資料,
Hive中包含以下資料模型:
**db:**在hdfs中表現為hive.metastore.warehouse.dir目錄下一個檔案夾
**table:**在hdfs中表現所屬db目錄下一個檔案夾
**external table:**資料存放位置可以在HDFS任意指定路徑
**partition:**在hdfs中表現為table目錄下的子目錄
**bucket:**在hdfs中表現為同一個表目錄下根據hash散列之后的多個檔案
4 常用操作
4.1 資料庫相關
Hive配置單元包含一個名為 default 默認的資料庫.
- —創建資料庫
create database [if not exists] ;
- –顯示所有資料庫
show databases;
- –洗掉資料庫
drop database if exists [restrict|cascade];
? 默認情況下,hive不允許洗掉含有表的資料庫,要先將資料庫中的表清空才能drop,否則會報錯
–加入cascade關鍵字,可以強制洗掉一個資料庫
hive> drop database if exists users cascade;
- –切換資料庫
use ;
4.2 內部表外部表
建內部表
create table
student(Sno int,Sname string,Sex string,Sage int,Sdept string)
row format delimited fields terminated by ',';
建外部表
create external table
student_ext(Sno int,Sname string,Sex string,Sage int,Sdept string)
row format delimited fields terminated by ',' location '/stu';
內 外部表加載資料:
load data local inpath '/root/hivedata/students.txt' overwrite into table student;
load data inpath '/stu' into table student_ext;
4.3 創建磁區表
- 磁區建表分為2種,一種是單磁區,也就是說在表檔案夾目錄下只有一級檔案夾目錄,另外一種是多磁區,表檔案夾下出現多檔案夾嵌套模式,
- 單磁區建表陳述句
create table day_table (id int, content string) partitioned by (dt string);
單磁區表,按天磁區,在表結構中存在id,content,dt三列,
- 雙磁區建表陳述句
create table day_hour_table (id int, content string) partitioned by (dt string, hour string);
雙磁區表,按天和小時磁區,在表結構中新增加了dt和hour兩列,
匯入資料
load data local inpath '/root/hivedata/dat_table.txt' into table day_table partition(dt='2017-07-07');
load data local inpath '/root/hivedata/dat_table.txt' into table day_hour_table partition(dt='2017-07-07', hour='08');
基于磁區的查詢:
SELECT day_table.* FROM day_table WHERE day_table.dt = '2017-07-07';
查看磁區
show partitions day_hour_table;
總的說來partition就是輔助查詢,縮小查詢范圍,加快資料的檢索速度和對資料按照一定的規格和條件進行管理,
-
指定分隔符
—指定分隔符創建磁區表
create table day_table (id int, content string) partitioned by (dt string) row format delimited fields terminated by ',';—復雜型別的資料表指定分隔符
資料如下
zhangsan beijing,shanghai,tianjin,hangzhou wangwu shanghai,chengdu,wuhan,haerbin建表陳述句
create table complex_array(name string,work_locations array<string>) row format delimited fields terminated by '\t' collection items terminated by ',';
4.4 增刪磁區
- 增加磁區
alter table t_partition add partition (dt='2008-08-08') location 'hdfs://node-21:9000/t_parti/';
執行添加磁區 /t_parti檔案夾下的資料不會被移動,并且沒有磁區目錄dt=2008-08-08
- 洗掉磁區
alter table t_partition drop partition (dt='2008-08-08');
執行洗掉磁區時/t_parti下的資料會被洗掉并且連同/t_parti檔案夾也會被洗掉
注意區別于load data時候添加磁區:會移動資料 會創建磁區目錄
4.5 hive中的join
準備資料
1,a
2,b
3,c
4,d
7,y
8,u
2,bb
3,cc
7,yy
9,pp
建表:
create table a(id int,name string)
row format delimited fields terminated by ',';
create table b(id int,name string)
row format delimited fields terminated by ',';
匯入資料:
load data local inpath '/root/hivedata/a.txt' into table a;
load data local inpath '/root/hivedata/b.txt' into table b;
實驗:
** inner join
select * from a inner join b on a.id=b.id;
+-------+---------+-------+---------+--+
| a.id | a.name | b.id | b.name |
+-------+---------+-------+---------+--+
| 2 | b | 2 | bb |
| 3 | c | 3 | cc |
| 7 | y | 7 | yy |
+-------+---------+-------+---------+--+
**left join
select * from a left join b on a.id=b.id;
+-------+---------+-------+---------+--+
| a.id | a.name | b.id | b.name |
+-------+---------+-------+---------+--+
| 1 | a | NULL | NULL |
| 2 | b | 2 | bb |
| 3 | c | 3 | cc |
| 4 | d | NULL | NULL |
| 7 | y | 7 | yy |
| 8 | u | NULL | NULL |
+-------+---------+-------+---------+--+
**right join
select * from a right join b on a.id=b.id;
select * from b right join a on b.id=a.id;
+-------+---------+-------+---------+--+
| a.id | a.name | b.id | b.name |
+-------+---------+-------+---------+--+
| 2 | b | 2 | bb |
| 3 | c | 3 | cc |
| 7 | y | 7 | yy |
| NULL | NULL | 9 | pp |
+-------+---------+-------+---------+--+
**
select * from a full outer join b on a.id=b.id;
+-------+---------+-------+---------+--+
| a.id | a.name | b.id | b.name |
+-------+---------+-------+---------+--+
| 1 | a | NULL | NULL |
| 2 | b | 2 | bb |
| 3 | c | 3 | cc |
| 4 | d | NULL | NULL |
| 7 | y | 7 | yy |
| 8 | u | NULL | NULL |
| NULL | NULL | 9 | pp |
+-------+---------+-------+---------+--+
**hive中的特別join
select * from a left semi join b on a.id = b.id;
select a.* from a inner join b on a.id=b.id;
+-------+---------
| a.id | a.name
+-------+---------
| 2 | b
| 3 | c
| 7 | y
+-------+---------
相當于
select a.id,a.name from a where a.id in (select b.id from b); 在hive中效率極低
select a.id,a.name from a join b on (a.id = b.id);
select * from a inner join b on a.id=b.id;
cross join(##慎用)
回傳兩個表的笛卡爾積結果,不需要指定關聯鍵,
select a.*,b.* from a cross join b;
4.6 json決議
1 先加載rating.json檔案到hive的一個原始表 rat_json
樣例:{"movie":"1193","rate":"5","timeStamp":"978300760","uid":"1"}
create table rat_json(line string) row format delimited;
load data local inpath '/root/hivedata/rating.json' into table rat_json;
2 需要決議json資料成四個欄位,插入一張新的表 t_rating
drop table if exists t_rating;
create table t_rating(movieid string,rate int,timestring string,uid string)
row format delimited fields terminated by '\t';
3 json表資料決議到rating表中
insert overwrite table t_rating
select
get_json_object(line,'$.movie') as moive,
get_json_object(line,'$.rate') as rate,
get_json_object(line,'$.timeStamp') as timestring, get_json_object(line,'$.uid') as uid
from rat_json limit 10;
5 常用函式
5.1 數值函式
-
指定精度取整函式 : round
語法: round(double a, int d)
回傳值: DOUBLE
說明: 回傳指定精度d的double型別
舉例:
hive> select round(3.1415926,4) from dual; 3.1416 -
向下取整函式 : floor
語法: floor(double a)
回傳值: BIGINT
說明: 回傳等于或者小于該double變數的最大的整數
舉例:
hive> select floor(3.1415926) from dual; 3 hive> select floor(25) from dual; 25 -
向上取整函式 : ceil
語法: ceil(double a)
回傳值: BIGINT
說明: 回傳等于或者大于該double變數的最小的整數
舉例:
hive> select ceil(3.1415926) from dual; 4 hive> select ceil(46) from dual; 46 -
取亂數函式 : rand
語法: rand(),rand(int seed)
回傳值: double
說明: 回傳一個0到1范圍內的亂數,如果指定種子seed,則會等到一個穩定的亂數序列
舉例:
hive> select rand() from dual; 0.5577432776034763 -
絕對值函式 : abs
語法: abs(double a) abs(int a)
回傳值: double int
說明: 回傳數值a的絕對值
舉例:
hive> select abs(-3.9) from dual; 3.9 hive> select abs(10.9) from dual; 10.9
5.2 日期函式
- to_date(string timestamp):回傳時間字串中的日期部分,
- 如to_date(‘1970-01-01 00:00:00’)=‘1970-01-01’
- current_date:回傳當前日期
- year(date):回傳日期date的年,型別為int
- 如year(‘2019-01-01’)=2019
- month(date):回傳日期date的月,型別為int,
- 如month(‘2019-01-01’)=1
- day(date): 回傳日期date的天,型別為int,
- 如day(‘2019-01-01’)=1
- weekofyear(date1):回傳日期date1位于該年第幾周,
- 如weekofyear(‘2019-03-06’)=10
- datediff(date1,date2):回傳日期date1與date2相差的天數
- 如datediff(‘2019-03-06’,‘2019-03-05’)=1
- date_add(date1,int1):回傳日期date1加上int1的日期
- 如date_add(‘2019-03-06’,1)=‘2019-03-07’
- date_sub(date1,int1):回傳日期date1減去int1的日期
- 如date_sub(‘2019-03-06’,1)=‘2019-03-05’
- months_between(date1,date2):回傳date1與date2相差月份
- 如months_between(‘2019-03-06’,‘2019-01-01’)=2
- add_months(date1,int1):回傳date1加上int1個月的日期,int1可為負數
- 如add_months(‘2019-02-11’,-1)=‘2019-01-11’
- last_day(date1):回傳date1所在月份最后一天
- 如last_day(‘2019-02-01’)=‘2019-02-28’
- next_day(date1,day1):回傳日期date1的下個星期day1的日期,day1為星期X的英文前兩字母
- 如next_day(‘2019-03-06’,‘MO’) 回傳’2019-03-11’
- **trunc(date1,string1)😗*回傳日期最開始年份或月份,string1可為年(YYYY/YY/YEAR)或月(MONTH/MON/MM),
- 如trunc(‘2019-03-06’,‘MM’)=‘2019-03-01’,trunc(‘2019-03-06’,‘YYYY’)=‘2019-01-01’
- unix_timestamp():回傳當前時間的unix時間戳,可指定日期格式,
- 如unix_timestamp(‘2019-03-06’,‘yyyy-mm-dd’)=1546704180
- from_unixtime():回傳unix時間戳的日期,可指定格式,
- 如select from_unixtime(unix_timestamp(‘2019-03-06’,‘yyyy-mm-dd’),‘yyyymmdd’)=‘20190306’
?
- 如select from_unixtime(unix_timestamp(‘2019-03-06’,‘yyyy-mm-dd’),‘yyyymmdd’)=‘20190306’
5.3 條件函式
- if(boolean,t1,t2):若布林值成立,則回傳t1,反正回傳t2,
- 如if(1>2,100,200)回傳200
- case when boolean then t1 else t2 end:若布林值成立,則t1,否則t2,可加多重判斷
- coalesce(v0,v1,v2):回傳引數中的第一個非空值,若所有值均為null,則回傳null,
- 如coalesce(null,1,2)回傳1
- isnull(a):若a為null則回傳true,否則回傳false
5.4 字串函式
- length(string1):回傳字串長度
- concat(string1,string2):回傳拼接string1及string2后的字串
- concat_ws(sep,string1,string2):回傳按指定分隔符拼接的字串
- lower(string1):回傳小寫字串,同lcase(string1),upper()/ucase():回傳大寫字串
- trim(string1):去字串左右空格,ltrim(string1):去字串左空格,rtrim(string1):去字串右空
- repeat(string1,int1):回傳重復string1字串int1次后的字串
- reverse(string1):回傳string1反轉后的字串,
- 如reverse(‘abc’)回傳’cba’
- rpad(string1,len1,pad1):以pad1字符右填充string1字串,至len1長度,
- 如rpad(‘abc’,5,‘1’)回傳’abc11’,lpad():左填充
- split(string1,pat1):以pat1正則分隔字串string1,回傳陣列,
- 如split(‘a,b,c’,’,’)回傳[“a”,“b”,“c”]
- substr(string1,index1,int1):以index位置起截取int1個字符,
- 如substr(‘abcde’,1,2)回傳’ab’
?
- 如substr(‘abcde’,1,2)回傳’ab’
5.5 型別轉換
? Hive的原子資料型別是可以進行隱式轉換的,類似于Java的型別轉換,例如某運算式使用INT型別,TINYINT會自動轉換為INT型別,但是Hive不會進行反向轉化,例如,某運算式使用TINYINT型別,INT不會自動轉換為TINYINT型別,它會回傳錯誤,除非使用CAST操作,
- cast(value AS TYPE)
- select cast(‘1’ as DOUBLE); 回傳1.0
6 hive常用的優化
6.1 Fetch抓取(Hive可以避免進行MapReduce)
? Hive中對某些情況的查詢可以不必使用MapReduce計算,例如:SELECT * FROM employees;在這種情況下,Hive可以簡單地讀取employee對應的存盤目錄下的檔案,然后輸出查詢結果到控制臺,
? 在hive-default.xml.template檔案中hive.fetch.task.conversion默認是more,老版本hive默認是minimal,該屬性修改為more以后,在全域查找 欄位查找 limit查找等都不走mapreduce,
案例實操:
? 1)把hive.fetch.task.conversion設定成none,然后執行查詢陳述句,都會執行mapreduce程式,
hive (default)> set hive.fetch.task.conversion=none;
hive (default)> select * from score;
hive (default)> select s_score from score;
hive (default)> select s_score from score limit 3;
2)把hive.fetch.task.conversion設定成more,然后執行查詢陳述句,如下查詢方式都不會執行mapreduce程式,
hive (default)> set hive.fetch.task.conversion=more;
hive (default)> select * from score;
hive (default)> select s_score from score;
hive (default)> select s_score from score limit 3;
6.2 本地模式
? 大多數的Hadoop Job是需要Hadoop提供的完整的可擴展性來處理大資料集的,不過,有時Hive的輸入資料量是非常小的,在這種情況下,為查詢觸發執行任務時消耗可能會比實際job的執行時間要多的多,對于大多數這種情況,Hive可以通過本地模式在單臺機器上處理所有的任務,對于小資料集,執行時間可以明顯被縮短,
? 用戶可以通過設定hive.exec.mode.local.auto的值為true,來讓Hive在適當的時候自動啟動這個優化,
set hive.exec.mode.local.auto=true; //開啟本地mr
//設定local mr的最大輸入資料量,當輸入資料量小于這個值時采用local mr的方式,默認為134217728,即128M
set hive.exec.mode.local.auto.inputbytes.max=51234560;
//設定local mr的最大輸入檔案個數,當輸入檔案個數小于這個值時采用local mr的方式,默認為4
set hive.exec.mode.local.auto.input.files.max=10;
案例實操:
1)開啟本地模式,并執行查詢陳述句
hive (default)> set hive.exec.mode.local.auto=true;
hive (default)> select * from score cluster by s_id;
18 rows selected (1.568 seconds)
2)關閉本地模式,并執行查詢陳述句
hive (default)> set hive.exec.mode.local.auto=false;
hive (default)> select * from score cluster by s_id;
18 rows selected (11.865 seconds)
6.3 磁區表分桶表
- 磁區表對sql過濾查詢是一種優化
- 分桶表對join操作時提升性能很大,桶為表加上了額外的結構,Hive 在處理有些查詢時能利用這個結構,具體而言,連接兩個在(包含連接列的)相同列上劃分了桶的表,可以使用 Map 端連接 (Map-side join)高效的實作,比如JOIN操作,對于JOIN操作兩個表有一個相同的列,如果對這兩個表都進行了桶操作,那么將保存相同列值的桶進行JOIN操作就可以,可以大大較少JOIN的資料量,
?
6.4 join優化
6.4.1 小表Join大表
- (新的版本當中已經沒有區別了,舊的版本當中需要使用小表)
1)將key相對分散,并且資料量小的表放在join的左邊,這樣可以有效減少記憶體溢位錯誤發生的幾率;再進一步,可以使用Group讓小的維度表(1000條以下的記錄條數)先進記憶體,在map端完成reduce,
2)多個表關聯時,最好分拆成小段,避免大sql(無法控制中間Job)
3)大表Join大表
(1)空KEY過濾
有時join超時是因為某些key對應的資料太多,而相同key對應的資料都會發送到相同的reducer上,從而導致記憶體不夠,此時我們應該仔細分析這些例外的key,很多情況下,這些key對應的資料是例外資料,我們需要在SQL陳述句中進行過濾,例如key對應的欄位為空,
對比如下:
不過濾
INSERT OVERWRITE TABLE jointable
SELECT a.* FROM nullidtable a JOIN ori b ON a.id = b.id;
結果:
No rows affected (152.135 seconds)
過濾
INSERT OVERWRITE TABLE jointable
SELECT a.* FROM (SELECT * FROM nullidtable WHERE id IS NOT NULL ) a JOIN ori b ON a.id = b.id;
結果:
No rows affected (141.585 seconds)
6.4.2 mapjoin
? 如果不指定MapJoin或者不符合MapJoin的條件,那么Hive決議器會將Join操作轉換成Common Join,即:在Reduce階段完成join,容易發生資料傾斜,可以用MapJoin把小表全部加載到記憶體在map端進行join,避免reducer處理,
1)開啟MapJoin引數設定:
(1)設定自動選擇Mapjoin
set hive.auto.convert.join = true; 默認為true
(2)大表小表的閾值設定(默認25M以下認為是小表):
set hive.mapjoin.smalltable.filesize=25123456;
6.5 group by
默認情況下,Map階段同一Key資料分發給一個reduce,當一個key資料過大時就傾斜了,
? 并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端進行部分聚合,最后在Reduce端得出最終結果,
1)開啟Map端聚合引數設定
? (1)是否在Map端進行聚合,默認為True
? set hive.map.aggr = true;
(2)在Map端進行聚合操作的條目數目
? set hive.groupby.mapaggr.checkinterval = 100000;
(3)有資料傾斜的時候進行負載均衡(默認是false)
? set hive.groupby.skewindata = true;
當選項設定為 true,生成的查詢計劃會有兩個MR Job,第一個MR Job中,Map的輸出結果會隨機分布到Reduce中,每個Reduce做部分聚合操作,并輸出結果,這樣處理的結果是相同的Group By Key有可能被分發到不同的Reduce中,從而達到負載均衡的目的;第二個MR Job再根據預處理的資料結果按照Group By Key分布到Reduce中(這個程序可以保證相同的Group By Key被分布到同一個Reduce中),最后完成最終的聚合操作,
6.6 Map數
-
通常情況下,作業會通過input的目錄產生一個或者多個map任務,
主要的決定因素有:input的檔案總個數,input的檔案大小,集群設定的檔案塊大小(目前為128M,可在hive中通過set dfs.block.size;命令查看到,該引數不能自定義修改);
-
舉例:
a) 假設input目錄下有1個檔案a,大小為780M,那么hadoop會將該檔案a分隔成7個塊(6個128m的塊和1個12m的塊),從而產生7個map數,
b) 假設input目錄下有3個檔案a,b,c大小分別為10m,20m,150m,那么hadoop會分隔成4個塊(10m,20m,128m,22m),從而產生4個map數,即,如果檔案大于塊大小(128m),那么會拆分,如果小于塊大小,則把該檔案當成一個塊,
-
是不是map數越多越好?
答案是否定的,如果一個任務有很多小檔案(遠遠小于塊大小128m),則每個小檔案也會被當做一個塊,用一個map任務來完成,而一個map任務啟動和初始化的時間遠遠大于邏輯處理的時間,就會造成很大的資源浪費,而且,同時可執行的map數是受限的,
-
是不是保證每個map處理接近128m的檔案塊,就高枕無憂了?
答案也是不一定,比如有一個127m的檔案,正常會用一個map去完成,但這個檔案只有一個或者兩個小欄位,卻有幾千萬的記錄,如果map處理的邏輯比較復雜,用一個map任務去做,肯定也比較耗時,
針對上面的問題3和4,我們需要采取兩種方式來解決:即減少map數和增加map數;
-
如何增加map數
如果表a只有一個檔案,大小為120M,但包含幾千萬的記錄,如果用1個map去完成這個任務,肯定是比較耗時的,這種情況下,我們要考慮將這一個檔案合理的拆分成多個,這樣就可以用多個map任務去完成,
set mapreduce.job.reduces =10; create table a_1 as select * from a distribute by rand(123);這樣會將a表的記錄,隨機的分散到包含10個檔案的a_1表中,再用a_1代替上面sql中的a表,則會用10個map任務去完成,
6.7 reduce數
- 調整reduce個數方法一
(1)每個Reduce處理的資料量默認是256MB
? hive.exec.reducers.bytes.per.reducer=256123456
(2)每個任務最大的reduce數,默認為1009
? hive.exec.reducers.max=1009
-
調整reduce個數方法二
在hadoop的mapred-default.xml檔案中修改
設定每個job的Reduce個數
set mapreduce.job.reduces = 15;
-
reduce個數并不是越多越好
1)過多的啟動和初始化reduce也會消耗時間和資源;
2)另外,有多少個reduce,就會有多少個輸出檔案,如果生成了很多個小檔案,那么如果這些小檔案作為下一個任務的輸入,則也會出現小檔案過多的問題;
在設定reduce個數的時候也需要考慮這兩個原則:處理大資料量利用合適的reduce數;使單個reduce任務處理資料量大小要合適;
6.8 jvm重用
? JVM重用是Hadoop調優引數的內容,其對Hive的性能具有非常大的影響,特別是對于很難避免小檔案的場景或task特別多的場景,這類場景大多數執行時間都很短,
? JVM重用可以使得JVM實體在同一個job中重新使用N次,N的值可以在Hadoop的mapred-site.xml檔案中進行配置,通常在10-20之間,具體多少需要根據具體業務場景測驗得出,
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>10</value>
<description>How many tasks to run per jvm. If set to -1, there is
no limit.
</description>
</property>
我們也可以在hive當中通過
set mapred.job.reuse.jvm.num.tasks=10;
這個設定來設定我們的jvm重用
缺點:
? 開啟JVM重用將一直占用使用到的task插槽,以便進行重用,直到任務完成后才能釋放,如果某個“不平衡的”job中有某幾個reduce task執行的時間要比其他Reduce task消耗的時間多的多的話,那么保留的插槽就會一直空閑著卻無法被其他的job使用,直到所有的task都結束了才會釋放,
6.9 資料壓縮與存盤格式
1.壓縮方式
壓縮可以節約磁盤的空間,基于文本的壓縮率可達40%+; 壓縮可以增加吞吐量和性能量(減小載入記憶體的資料量),但是在壓縮和解壓程序中會增加CPU的開銷,所以針對IO密集型的jobs(非計算密集型)可以使用壓縮的方式提高性能, 幾種壓縮演算法:

2.存盤格式
-
TextFile
Hive資料表的默認格式,存盤方式:行存盤, 可以使用Gzip壓縮演算法,但壓縮后的檔案不支持split 在反序列化程序中,必須逐個字符判斷是不是分隔符和行結束符,因此反序列化開銷會比SequenceFile高幾十倍, -
Sequence Files
Hadoop中有些原生壓縮檔案的缺點之一就是不支持分割,支持分割的檔案可以并行 的有多個mapper程式處理大資料檔案,大多數檔案不支持可分割是因為這些檔案只能從頭開始讀,Sequence File是可分割的檔案格式,支持Hadoop的block級壓縮, Hadoop API提供的一種二進制檔案,以key-value的形式序列化到檔案中,存盤方式:行存盤, sequencefile支持三種壓縮選擇:NONE,RECORD,BLOCK,Record壓縮率低,RECORD是默認選項,通常BLOCK會帶來較RECORD更好的壓縮性能, 優勢是檔案和hadoop api中的MapFile是相互兼容的 -
RCFile
存盤方式:資料按行分塊,每塊按列存盤,結合了行存盤和列存盤的優點: 首先,RCFile 保證同一行的資料位于同一節點,因此元組重構的開銷很低 其次,像列存盤一樣,RCFile 能夠利用列維度的資料壓縮,并且能跳過不必要的列讀取 資料追加:RCFile不支持任意方式的資料寫操作,僅提供一種追加介面,這是因為底層的 HDFS當前僅僅支持資料追加寫檔案尾部, 行組大小:行組變大有助于提高資料壓縮的效率,但是可能會損害資料的讀取性能,因為這樣增加了 Lazy 解壓性能的消耗,而且行組變大會占用更多的記憶體,這會影響并發執行的其他MR作業, -
ORCFile
存盤方式:資料按行分塊,每塊按照列存盤, 壓縮快,快速列存取,效率比rcfile高,是rcfile的改良版本, -
Parquet
Parquet也是一種行式存盤,同時具有很好的壓縮性能;同時可以減少大量的表掃描和反序列化的時間 -
自定義格式
可以自定義檔案格式,用戶可通過實作InputFormat和OutputFormat來自定義輸入輸出格式,
結論,一般選擇orcfile/parquet + snappy 的方式
create table tablename (
xxx,string
xxx, bigint
)
ROW FORMAT DELTMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties("orc.compress" = "SNAPPY")
6.10 并行執行
- 當一個sql中有多個job時候,且這多個job之間沒有依賴,則可以讓順序執行變為并行執行(一般為用到union all )
// 開啟任務并行執行
set hive.exec.parallel=true;
// 同一個sql允許并行任務的最大執行緒數
set hive.exec.parallel.thread.number=8;
6.11 合并小檔案
? 小檔案的產生有三個地方,map輸入,map輸出,reduce輸出,小檔案過多也會影響hive的分析效率:
設定map輸入的小檔案合并
set mapred.max.split.size=256000000;
//一個節點上split的至少的大小(這個值決定了多個DataNode上的檔案是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一個交換機下split的至少的大小(這個值決定了多個交換機上的檔案是否需要合并)
set mapred.min.split.size.per.rack=100000000;
//執行Map前進行小檔案合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
設定map輸出和reduce輸出進行合并的相關引數:
//設定map端輸出進行合并,默認為true
set hive.merge.mapfiles = true
//設定reduce端輸出進行合并,默認為false
set hive.merge.mapredfiles = true
//設定合并檔案的大小
set hive.merge.size.per.task = 256*1000*1000
//當輸出檔案的平均大小小于該值時,啟動一個獨立的MapReduce任務進行檔案merge,
set hive.merge.smallfiles.avgsize=16000000
7 hive的資料傾斜
表現:任務進度長時間維持在99%(或100%),查看任務監控頁面,發現只有少量(1個或幾個)reduce子任務未完成,因為其處理的資料量和其他reduce差異過大,
原因:某個reduce的資料輸入量遠遠大于其他reduce資料的輸入量
-
key分布不均勻
-
業務資料本身的特性
-
建表時考慮不周
-
某些SQL陳述句本身就有資料傾斜

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/321148.html
標籤:其他
