详解 Hive 分区表和分桶表

发布于:2024-05-21 ⋅ 阅读:(139) ⋅ 点赞:(0)

一、分区表

1. 介绍

  • 分区表实际上是对应一个 HDFS 文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件
  • Hive 中的分区就是分目录,即把一个大的数据集根据业务需要分割成小的数据集
  • 在查询时通过 WHERE 子句中的表达式选择查询所需要的指定的分区,可以避免全表扫描,进而提高查询效率

2. 基本操作

2.1 数据准备
  • 原始数据文件

    -- dept_1.log
    10  ACCOUNTING  1700
    20  RESEARCH  1800
    
    -- dept_2.log
    30  SALES  1900
    40  OPERATIONS  1700
    
    -- dept_3.log
    50  TEST  2000
    60  DEV 1900
    
  • 创建分区表

    --使用 partitioned by 设置分区字段,分区字段不能是表中已存在的字段
    create table if not exists dept_par
    (
    	deptNo int,
        deptName string,
        loc int
    )
    partitioned by (idate string)
    row format delimited fields terminated by '\t';
    
  • 加载数据到分区表

    --加载数据时使用 partition 指定分区
    load data local inpath '/opt/module/hive/datas/dept_1.log' into table dept_par 
    partition(idate='2022-04-01');
    
    load data local inpath '/opt/module/hive/datas/dept_2.log' into table dept_par 
    partition(idate='2022-04-02');
    
    load data local inpath '/opt/module/hive/datas/dept_3.log' into table dept_par 
    partition(idate='2022-04-03');
    
2.2 查询分区
select * from dept_par where idate='2022-04-01';
2.3 增加分区
-- 创建单个分区
alter table dept_par add partition(idate='2022-04-04');
-- 创建多个分区(空格划分)
alter table dept_par add partition(idate='2022-04-05') partition(idate='2022-04-06');
2.4 删除分区
-- 删除单个分区
alter table dept_par drop partition(idate='2022-04-06');
-- 删除多个分区(逗号划分)
alter table dept_par drop partition(idate='2022-04-04'), partition(idate='2022-04-05');
2.5 查看分区
-- 查看分区表的分区个数
show partitions dept_par;

-- 查看分区表结构
desc formatted dept_par;

3. 二级分区

3.1 数据准备
  • 创建二级分区表

    create table if not exists dept_par2
    (
    	deptNo int,
        deptName String,
        loc int
    )
    partitioned by (iDate string, hour string)
    row format delimited fields terminated by '\t';
    
  • 加载数据到二级分区表

    load data local inpath '/opt/module/hive/datas/dept_1.log' into table dept_par2
    partition(iDate='20220401',hour='10');
    
    load data local inpath '/opt/module/hive/datas/dept_2.log' into table dept_par2
    partition(iDate='20220401',hour='11');
    
    load data local inpath '/opt/module/hive/datas/dept_3.log' into table dept_par2
    partition(iDate='20220402',hour='10');
    
3.2 查询
select * from dept_par2 where iDate='20220401' and hour='10';
3.3 同步分区表元数据和数据
  • 问题:

    -- 普通表
    -- 1.使用 hadoop 命令创建目录并上传数据
    hadoop fs -mkdir -p /user/hive/warehouse/mydb.db/dept
    hadoop fs -put dept_1.log /user/hive/warehouse/mydb.db/dept
    -- 2.创建表
    create table if not exists dept(deptNo int,deptName string,loc string)
    row format delimited fields terminated by '\t';
    -- 3.查询
    select * from dept;  -- 有数据
    
    -- 分区表
    -- 1.使用 hadoop 命令创建目录并上传数据
    hadoop fs -mkdir -p /user/hive/warehouse/mydb.db/dept_par3/iDate=20220403
    hadoop fs -put dept_1.log /user/hive/warehouse/mydb.db/dept_par3/iDate=20220403
    -- 2.创建表
    create table if not exists dept_par3(deptNo int,deptName string,loc string)
    partitioned by (iDate string)
    row format delimited fields terminated by '\t';
    -- 3.查询
    select * from dept_par3;  -- 没有数据
    
    
    -- 结论:分区表中由于多了分区信息,直接创建分区目录不会在元数据中添加分区信息,从而导致查询目录无法匹配
    
  • 解决方法:

    • 分区修复

      msck repair table dept_par3;
      
    • 执行增加分区命令

      alter table dept_par3 add partition(iDate='20220403');
      
    • load 数据到分区

      load data local inpath '/opt/module/hive/datas/dept_1.log' into table dept_par3
      partition(iDate='20220403');
      

4. 动态分区调整

动态分区机制:对分区表 Insert 数据时, 自动根据分区字段的值,将数据插入到相应的分区中

4.1 参数配置
  • 开启动态分区功能(默认 true,开启)

    set hive.exec.dynamic.partition=true;
    
  • 设置为非严格模式(默认 strict,表示必须指定至少一个分区为静态分区,nonstrict 模式表示允许所有的分区字段都可以使用动态分区)

    set hive.exec.dynamic.partition.mode=nonstrict;
    
  • 在所有执行 MR 的节点上,最大一共可以创建多少个动态分区。默认 1000

    set hive.exec.max.dynamic.partitions=1000;
    
  • 在每个执行 MR 的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。比如:源数据中包含了一年的数据,即 day 字段有 365 个值,那么该参数就要设置成大于 365,如果使用默认值 100,则会报错

    set hive.exec.max.dynamic.partitions.pernode=100;
    
  • 整个 MR Job 中,最大可以创建多少个 HDFS 文件。默认 100000

    set hive.exec.max.created.files=100000;
    
  • 当有空分区生成时,是否抛出异常。一般不需要设置。默认 false

    set hive.error.on.empty.partition=false;
    
4.2 案例
  • 需求:将 dept 表中的数据按照地区(loc 字段),插入到目标表 dept_par 的相应分区中

  • 实现:

    • 创建目标分区表

      create table dept_par_dy(deptNo int, deptName string) 
      partitioned by (loc int) 
      row format delimited fields terminated by '\t';
      
    • 动态分区导入数据

      insert into table dept_par_dy partition(loc)
      select deptNo, deptName, loc from dept;
      
    • 查看分区数

      show partitions dept_par_dy;
      
4.3 Hive 3.x 新特性
  • 导入数据是 partition 关键词可以省略

    -- 等价
    insert into table dept_par_dy partition(loc)
    select deptNo, deptName, loc from dept;
    
    insert into table dept_par_dy
    select deptNo, deptName, loc from dept;
    
  • 可以在严格模式下进行动态分区

    set hive.exec.dynamic.partition.mode=strict;
    
    insert into table dept_par_dy
    select deptNo, deptName, loc from dept;
    

二、分桶表

1. 介绍

  • 对于一张表或者分区,Hive 可以进一步组织成桶,进行更为细粒度的数据范围划分
  • 分桶是将数据集分解成更容易管理的若干部分的另一个技术
  • 分区针对的是数据的存储路径;分桶针对的是数据文件

2. 基本操作

2.1 数据准备
  • 原始数据

    -- stu.txt
    1001  ss1
    1002  ss2
    1003  ss3
    1004  ss4
    1005  ss5
    1006  ss6
    1007  ss7
    1008  ss8
    1009  ss9
    1010  ss10
    1011  ss11
    1012  ss12
    1013  ss13
    1014  ss14
    1015  ss15
    1016  ss16
    
  • 创建分桶表

    create tabble if not exists stu_buck
    (
    	id int,
        name string
    )
    clustered by (id) into 4 buckets
    row format delimited fields terminated by '\t';
    
  • 加载数据到分桶表

    load data local inpath '/opt/module/hive/datas/stu.txt' into table stu_buck;
    
2.2 操作
  • 查看分桶信息

    desc formatted stu_buck;
    
  • 查询

    select * from stu_buck;
    
2.3 分桶规则

对分桶字段的值进行哈希运算,然后除以桶的个数取余数,从而决定该条记录存放在哪个桶当中

2.4 注意事项
  • reduce 的个数设置为 -1,让 Job 自行决定需要用多少个 reduce 或者将 reduce 的个数设置为大于等于分桶表的桶数
  • 从 hdfs 中 load 数据到分桶表中,避免本地文件找不到问题
  • 不要使用本地模式