前言:
互聯網應用, 當Mysql單機遇到性能瓶頸時, 往往采用的優化策略是分庫分表. 由於互聯網應用普遍的弱事務性, 這種優化效果非常的顯著.而Hive作為數據倉庫, 當數據量達到一定數量時, 查詢性能會有所下降, 那如何利用數據的特點進行優化? 分區分桶作為Hive的優化的一個有力武器.
*). 分區(靜態、動態)
Hive沒有索引, 查詢中一般會掃描整個表內容,會消耗很多時間做沒必要的工作。倘若只需要掃描表中關心的一部分數據,因此建表時引入了partition概念。分區表指的是在創建表時指定的partition的分區空間。
1). 靜態分區
hive默認采用靜態分區, 數據的導入需至少指定一個分區字段
1.1). 創建分區表
CREATE TABLE tb_part_shop ( shop_id int, shop_name string, shopkeeper string ) PARTITIONED BY (province_id int, city_id int) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
1.2). 描述分區表(describe extended <table_name>)
DESCRIBE EXTENDED tb_part_shop;
> DESCRIBE EXTENDED tb_part_shop; OK shop_id int None shop_name string None shopkeeper string None province_id int None city_id int None # Partition Information # col_name data_type comment province_id int None city_id int None
1.3). 導入分區和數據
ALTER TABLE tb_part_shop ADD PARTITION (province_id = 1001, city_id = 10001);
數據內容
33068201 Wal-Mart wal-mart
33068202 Carrefour carrefour
LOAD DATA LOCAL INPATH '/path/to/data.txt' INTO TABLE tb_part_shop PARTITION(province_id = 1001, city_id = 10001);
對於小數據量導入, 可采用如下的語句來實現
INSERT INTO VALUES() 等價實現 INSERT INTO TABLE <table_name> SELECT ... FORM <table_name> LIMIT 1;
1.4). 分區表的目錄結構
分區表, 在hdfs中的目錄結構如圖所示:
2). 動態分區表
2.1). 設置開啟動態分區開關
set hive.exec.dynamic.partition=true;
2.2). 嚴格模式
set hive.exec.dynamic.partition.mode=strict; # strict/nonstrict
默認為strict, 對於分區表, 若插入語句沒有指定至少一個靜態分區字段, 則執行失敗
如下例子:
set hive.exec.dynamic.partition.mode=strict;
hive> insert into table tb_part_shop select 1, "2haodian", "shopper", 1001, 20012 from tb_user limit 1;
FAILED: SemanticException 1:18 Need to specify partition columns because the destination table is partitioned. Error encountered near token 'tb_part_shop'
2.3). 其他限制條件
set hive.exec.max.dynamic.partitions=3000; # 具體的數值, 表示總共能創建的動態分區數
set hive.exec.max.dynamic.partitions.pernode=1000; # 在mapper/reducer節點中, 允許創建的分區數
SHOW PARTITIONS tb_part_shop;
分區適合於字段值可枚舉, 離散有限個數值, 比如按時間年/月/日, 省份/市區號編碼, 而不適合取值特別多的應用場景, 因為一個值就對應一個目錄, 目錄無休止的增加對查詢的性能, 反而是有害的.
*). 分桶
Hive采用對列值哈希來組織數據的方式, 稱之為分桶, 適合采樣和map-join.
看看分桶表如何建立
1). 創建分桶表
CREATE TABLE tb_bucket_shop ( shop_id int, shop_name string, shopkeeper string ) CLUSTERED BY (shop_id) INTO 4 BUCKETS ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
2). 數據導入
set hive.enforce.bucketing=true;
INSERT OVERWRITE TABLE tb_bucket_shop SELECT shop_id, shop_name, shopkeeper FROM tb_part_shop CLUSTER BY shop_id;
若沒有使用hive.enforce.bucketing屬性, 則需要設置和分桶個數相匹配的reducer個數, 同時SELECT后添加CLUSTER BY
set mapred.reduce.tasks=4;
INSERT OVERWRITE TABLE tb_bucket_shop SELECT shop_id, shop_name, shopkeeper FROM tb_part_shop CLUSTER BY shop_id;
分桶適合於sampling, 不過其數據正確的導入到hive表中, 需要用戶自己來保證, 因為table中信息僅僅是元數據, 而不影響實際填充表的命令.
總結:
分區分桶是hive性能優化的一個手段, 不同的字段, 其數值屬性不同, 其對應的優化方式也不同. 也不能簡單的認為分區分桶對應傳統關系型數據庫的分庫分表, 完全不一樣.