前言:

  互联网应用, 当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中的目录结构如图所示:

hive 分区分桶 hive 分区和分桶_hive 分区分桶

  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 分区分桶 hive 分区和分桶_mysql集群_02

  分区适合于字段值可枚举, 离散有限个数值, 比如按时间年/月/日, 省份/市区号编码, 而不适合取值特别多的应用场景, 因为一个值就对应一个目录, 目录无休止的增加对查询的性能, 反而是有害的. 

*). 分桶
  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性能优化的一个手段, 不同的字段, 其数值属性不同, 其对应的优化方式也不同. 也不能简单的认为分区分桶对应传统关系型数据库的分库分表, 完全不一样.