轉自:http://www.aahyhaa.com/archives/316
hive引入partition和bucket的概念,中文翻譯分別為分區和桶(我覺的不是很合適,但是網上基本都是這么翻譯,暫時用這個吧),這兩個概念都是把數據划分成塊,分區是粗粒度的划分桶是細粒度的划分,這樣做為了可以讓查詢發生在小范圍的數據上以提高效率。
首先介紹分區的概念,還是先來個例子看下如果創建分區表:
[code lang=”sql”]
create table logs_partition(ts bigint,line string) –ts timestamp line 每一行日志
partitioned by (dt string,country string) — 分區列 dt 日志產生日期
[/code]
創建分區表需要在定義表的時候聲明分區列,這個分區列是個比較有意思的東西下面來看看,向表中導入數據:
[code lang=”sql”]
load data local inpath ‘input/hive/partitions/file1′
into table logs_partition
partition(dt=’2001-01-01′,country=’GB’);
…….
— 看下表的結構
hive> desc logs_partition;
OK
ts bigint None
line string None
dt string None
country string None
# Partition Information
# col_name data_type comment
dt string None
country string None
Time taken: 0.265 seconds, Fetched: 10 row(s)
查看一個表的所有分區
hive> show partitions logs_partition;
OK
dt=2001-01-01/country=GB
dt=2001-01-01/country=US
dt=2001-01-02/country=GB
dt=2001-01-02/country=US
Time taken: 0.186 seconds, Fetched: 4 row(s)
[/code]
導入完數據后看下hive數據倉庫表logs_partition下的文件目錄結構
/user/hive/warehouse/logs_partition
看到了吧分區列都成了目錄了,這樣查詢的時候就會定位到某個目錄下而大大提高了查詢效率,在查看表結構的時候分區列跟其他列並無區別,看個查詢語句:
[code lang=”sql”]
SELECT ts, dt, line
FROM logs
WHERE country=’GB’;
1 2001-01-01 Log line 1
2 2001-01-01 Log line 2
4 2001-01-02 Log line 4
Time taken: 36.316 seconds, Fetched: 3 row(s)
[/code]
這個查詢只會查詢file1, file2, file4這三個文件還有一個有趣的問題就是,查看下數據文件fieldX
里面都只包含兩列ts和line並不包含dt和country這兩個分區列,但是從查詢結果看分區列和非分區列並無差別,實際上分區列都是從數據倉庫的分區目錄名得來的。
接下來說說桶,桶是更為細粒度的數據范圍划分,它能使一些特定的查詢效率更高,比如對於具有相同的桶划分並且jion的列剛好就是在桶里的連接查詢,還有就是示例數據,對於一個龐大的數據集我們經常需要拿出來一小部分作為樣例,然后在樣例上驗證我們的查詢,優化我們的程序。
下面看看如何創建帶桶的表
[code lang=”sql”]
create table bucket_user (id int,name string)
clustered by (id) into 4 buckets;
[/code]
關鍵字clustered聲明划分桶的列和桶的個數,這里以用戶的id來划分桶,划分4個桶。
以下為了簡便划分桶的列簡稱為桶列
hive會計算桶列的hash值再以桶的個數取模來計算某條記錄屬於那個桶
向這種帶桶的表里面導入數據有兩種方式,一種是外部生成的數據導入到桶表,一種是利用hive來幫助你生成桶表數據
由於hive在load數據的時候不能檢查數據文件的格式與桶的定義是否匹配,如果不匹配在查詢的時候就會報錯,所以最好還是讓hive來幫你生成數據,簡單來說就是利用現有的表的數據導入到新定義的帶有桶的表中,下面來看看:
已經存在的表:
[code lang=”bash”]
hive> select * from users;
OK
0 Nat
2 Joe
3 Kay
4 Ann
hive> set hive.enforce.bucketing=true –必須設置這個數據,hive才會按照你設置的桶的個數去生成數據
[/code]
下面把user的數據導入到bucketed_users中
[code language=”lang='sql”]
insert overwrite table bucketed-users
select * from users;
[/code]
然后見證奇跡的時刻:
[code lang=”bash”]
hive> dfs -ls /user/hive/warehouse/bucketed_users;
-rw-r–r– 1 root supergroup 12 2013-10-10 18:48 /user/hive/warehouse/bucketed_users/000000_0
-rw-r–r– 1 root supergroup 0 2013-10-10 18:48 /user/hive/warehouse/bucketed_users/000001_0
-rw-r–r– 1 root supergroup 6 2013-10-10 18:48 /user/hive/warehouse/bucketed_users/000002_0
-rw-r–r– 1 root supergroup 6 2013-10-10 18:48 /user/hive/warehouse/bucketed_users/000003_0
hive> dfs -cat /user/hive/warehouse/bucketed_users/000000_0;
0Nat
4Ann
[/code]
下面來看看利用bucket來對示例數據進行查詢
[code lang=”sql”]
—帶桶的表
select * from bucketed_users
tablesample(bucket 1 out of 4 on id);
—不帶桶的表
select * from users
tablesample(bucket 1 out of 4 on rand());
[/code]
tablesample的作用就是讓查詢發生在一部分桶上而不是整個數據集上,上面就是查詢4個桶里面第一個桶的數據
相對與不帶桶的表這無疑是效率很高的,因為同樣都是需要一小部分數據,但是不帶桶的表需要使用rand()函數,需要在整個數據集上檢索。