1. 程式人生 > >hive詳解(三)

hive詳解(三)

分割槽&分桶

分割槽

為什麼有分割槽?

隨著系統執行時間增長,表的資料量越來越大,而hive查詢時通常是是全表掃描,這樣將導致大量的不必要的資料掃描,從而大大減低查詢效率。

從而引進分割槽技術,使用分割槽技術,避免hive全表掃描,提升查詢效率。

可以將使用者的整個表的資料在儲存時劃分到多個子目錄,從而在查詢時可以指定查詢條件(子目錄以分割槽變數的值來命名)eg:year=‘2018’。

怎麼分割槽?

根據業務,通常按照年、月、日、地區等

分割槽的技術?

PARTIONED BY(col_name data_type) hive的分割槽欄位使用的是表外欄位。而mysql使用的是表內欄位。 1、hive的分割槽名區分大小寫 2、hive的分割槽本質是在表目錄下面建立目錄,但是該分割槽欄位是一個偽列,不真實存在於資料中 3、一張表可以有一個或者多個分割槽,分割槽下面也可以有一個或者多個分割槽

分割槽的意義?

可以讓使用者在做資料分析統計時縮小資料掃描的範圍,因為可以在select時指定要統計的分割槽,提高查詢效率。

建立分割槽表

一級:

create table if not exists part1(
uid int,
uname string,
uage int
)
PARTITIONED BY (country string)
row format delimited 
fields terminated by ','
;

分割槽表匯入資料的方式:

load data local inpath '/usr/local/xxx' into table part1
partition(country='China'); #要指定分割槽

select * from part1 where country='China';	

二級:

create table if not exists part2(
uid int,
uname string,
uage int
)
PARTITIONED BY (year string,month string)
row format delimited 
fields terminated by ','
;


load data local inpath '/usr/local/xxx' into table part1
partition(year='2018',month='09'); 

load data local inpath '/usr/local/xxx' into table part1
partition(year='2018',month=09); 

select * from part2 where year='2018',month='09';

三級:

create table if not exists part3(
uid int,
uname string,
uage int
)
PARTITIONED BY (year string,month string,day string)
row format delimited 
fields terminated by ','
;


load data local inpath '/usr/local/xxx' into table part3
partition(year='2018',month='09',day='29'); 

load data local inpath '/usr/local/xxx' into table part3
partition(year='2018',month=09,day='29'); 

select * from part3 where year='2018',month='09',day='29';

顯示分割槽:

show partitions part3;

修改分割槽: 分割槽名不能使用命令修改(手動修改),檔名+元資料 增加分割槽:

alter table part1 add partition(country='india');

增加多個分割槽:

alter table part1 add partition(country='india') partition(country='korea') partition(country='America');

增加分割槽並設定資料:

alter table part1 add partition(country='Vietnam')
location '/user/hive/warehouse/xxx'
;

增加分割槽並設定資料: location 跟在 partition之後,空格隔開

修改分割槽的儲存路徑:(hdfs的路徑必須是全路徑)

alter table part1 partition(country='Vietnam') set location ‘hdfs://hadoop01:9000/user/hive/warehouse/brz.db/part1/country=Vietnam’

刪除分割槽:

alter table part1 drop partition(country='india');

alter table part1 drop partition(country='india'),partition(country='korea'),partition(country='America'); ##逗號隔開

分割槽型別: 1、靜態分割槽:載入資料到指定的分割槽值 2、動態分割槽:資料未知,根據分割槽的值確定建立分割槽 3、混合分割槽:靜態和動態都有

動態分割槽的屬性: set hive.exec.dynamic.partition=true;//(true/false) set hive.exec.dynamic.partition.mode=strict;//(strict/nonstrict) 至少有一個靜態的值 set hive.exec.dynamic.partitions=1000;//(分割槽最大數) set hive.exec.max.dynamic.partitions.pernode=100

建立動態分割槽:

create table if not exists dt_part1(
uid int,
uname string,
uage int
)
PARTITIONED BY (year string,month string)
row format delimited 
fields terminated by ','
;

載入資料:(不能使用load載入資料) load data local inpath ‘/usr/local/xxx’ into table part1 partition(year,month); 載入資料:(使用 insert into方式載入資料) 1、建立臨時表

create table if not exists part_tmp(
uid int,
uname string,
uage int,
year string,
month string
)
row format delimited 
fields terminated by ','
;

insert into dy_part1 partition(year,month)
select * from part_tmp
;

混合:(注意列的個數的匹配)

create table if not exists dy_part2(
uid int,
uname string,
uage int
)
PARTITIONED BY (year string,month string)
row format delimited 
fields terminated by ','
;

insert into dy_part2 partition(year='2018',month)
select uid,uname,uage,month from part_tmp
;

###設定hive的執行模式: 1、嚴格模式:

set hive.mapred.mode=nonstrict/strict

In strict mode, some risky queries are not allowed to run. They include: Cartesian Product. No partition being picked up for a query. Comparing bigints and strings. Comparing bigints and doubles. Orderby without limit.

注意事項: 1、hive的分割槽使用的表外欄位,分割槽欄位是一個偽列但是可以查詢過濾。 2、分割槽欄位不建議使用中文 3、不太建議使用動態分割槽。因為動態分割槽將會使用mapreduce來查詢資料,如果分割槽數量過多將導致namenode和yarn的資源瓶頸。所以建議動態分割槽前也儘可能之前預知分割槽數量。 4、分割槽屬性的修改均可以使用手動元資料和hdfs的資料內容

分桶

為什麼要分桶?

單個分割槽或者表中的資料量越來越大,當分割槽不能更細粒的劃分資料時,所以會採用分桶技術將資料更細粒度的劃分和管理。

分桶技術

[CLUSTERED BY (col_name, col_name, ...) 
[SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] 
關鍵字:BUCKET

分桶的意義 ###:

1、為了儲存分桶查詢結果的分桶結構(資料已經按照分桶欄位進行了hash雜湊) 2、分桶表資料進行抽樣和JOIN時可以提高MR程式效率

分桶表的使用 ###:

1、建立一個帶分桶定義的表(分桶表)

create table if not exists buc1(
uid int,
uname string,
uage int
)
clustered by (uid) into 4 buckets
row format delimited
fields terminated by ','
;

載入資料:

load data local inpath '/usr/local/hive/test/3.txt' into table buc1
;

設定強制分桶屬性:

set hive.enforce.bucketing=false/true

如果reduce的個數和分桶的個數不一致時,請手動設定reduce的個數: 設定reduce task的個數:

set mapreduce.job.reduces=4;

分桶查詢測試:

select * from buc1
cluster by (uid)
;

建立臨時表:

create table if not exists buc_temp(
uid int,
uname string,
uage int
)
row format delimited
fields terminated by ','
;

載入資料:

load data local inpath '/usr/local/hivedata/3.txt' into table buc_temp
;

建立分桶表:

create table if not exists buc2(
uid int,
uname string,
uage int
)
clustered by (uid) into 4 buckets
row format delimited
fields terminated by ','
;

分桶表資料需要使用insert into 方式來載入:

insert overwrite table buc2
select uid,uname,uage from buc_temp
cluster by (uid)
;

建立分桶表,並且指定排序欄位及排序規則

create table if not exists buc3(
uid int,
uname string,
uage int
)
clustered by (uid) 
sorted by (uid desc) into 4 buckets
row format delimited
fields terminated by ','
;

匯入資料:

insert overwrite table buc3
select uid,uname,uage from buc_temp
cluster by (uid)
;

insert overwrite table buc3
select uid,uname,uage from buc_temp
distribute by (uid) sort by (uid asc)
;

insert overwrite table buc3
select uid,uname,uage from buc_temp
distribute by (uid) sort by (uid desc)
;

insert overwrite table buc3
select uid,uname,uage from buc_temp
distribute by (uid) sort by (uage desc)
;

對分桶表的查詢 :

1、查詢全部:

select * from buc3;
select * from buc3 tablesample(bucket 1 out of 1)  

查詢第幾桶:

select * from buc3 tablesample(bucket 1 out of 4 on uid);                            //除4餘0
select * from buc3 tablesample(bucket 1 out of 2 on uid);  

解釋一下:

tablesample(bucket x out of y on uid)  
x:代表從第幾桶開始查詢
y:查詢的總桶數,y可以是總的桶數的倍數或者因子;x不能大於y

不壓縮不拉伸:1 out of 4
for 1 to 4
1 2 3 4 1 2 3 4
1       1 + 4

壓縮: 1 out of 2
1 2 3 4
1 2 1 2 1 2
1   1 + 4/2 1+4/2+4/2

拉伸:1 out of 8
1 2 3 4 5 6 7 8
1 2 3 4

等於是重新對所有資料進行分桶:

例子: 查詢uid為奇數:(tablesample一定要緊跟在表名之後)

select * from buc3 tablesample(bucket 2 out of 2 on uid)

查詢:

select * from part_tmp limit 3;
select * from part_tmp tablesample(3 rows);
select * from part_tmp tablesample(13 percent);
select * from part_tmp tablesample(56B); ###k B M G T P

隨機查詢3條資料:

select * from part_tmp order by rand() limit 3;
select rand() as rand1,* from part_tmp;

分桶總結:

1、定義: clustered by (uid) – 指定分桶的欄位 sorted by (uid desc) – 指定資料的排序規則,表示預期的資料就是以這裡設定的欄位以及排序規則來進行儲存

2、導資料 cluster by (uid) – 指定getPartition以哪個欄位來進行hash雜湊,並且排序欄位也是指定的欄位,預設以正序進行排序

distribute by(uid) – 指定getPartition以哪個欄位來進行hash雜湊

sort by(uid asc) – 指定排序欄位,以及排序規則 –更靈活的方式,這種資料獲取方式可以分別指定getPartition的欄位和sort的欄位

cluster by (uid)與distribute by(uid) sort by (uid asc)結果是一樣的

分割槽下的分桶

舉例說明一下:按照性別進行分割槽(1男2女),在分割槽中按照uid的奇偶進行分桶:

1 gyy1 1
2 gyy2 2
3 gyy3 2
4 gyy4 1
5 gyy5 2
6 gyy6 1
7 gyy7 1
8 gyy8 2
9 gyy9 1
10 gyy10 1
11 gyy11 2
12 gyy12 1

1、建立臨時表:

create table if not exists stu_temp(
uid int,
uname string,
usex int
)
row format delimited 
fields terminated by ' '
;

載入資料:

load data local inpath '/usr/local/hivedata/stu.dat' into table stu_temp;

建立分割槽分桶表:

create table if not exists stus(
uid int,
uname string
)
partitioned by (sex int)
clustered by (uid) into 2 buckets
row format delimited 
fields terminated by ' '
;

//insert into方式:

insert into table stus partition(sex)
select uid,uname,usex from stu_temp
cluster by (uid)
;

需求: 查詢性別為女性的、並且學號為奇數的學生:

select *
from stus tablesample(bucket 2 out of 2 on uid)
where sex=2;

注意: 1、分割槽使用的是表外欄位,分桶使用的是表內欄位 2、分桶是更細粒度的劃分、管理資料,更多用來做資料抽樣、JOIN操作