背景

博主所在的公司是一家手机游戏发行公司,旗下多款手机游戏,每小时游戏日志上报量非常大,这些原始游戏日志全部进入到我司数据仓库 ods 层,运营,产品每天会查询游戏上报的原始日志(日志中包含abtest),分析数据走向。但是因为每天的日志数量非常大,且所有游戏的日志都混合在一张原始日志表中(没有对游戏上报日志在 ods 层做分游戏处理,类似 ods_game1, ods_game2,…),于是问题就产生了,运营和产品同时查询多天的原始数据日志(分析数据时都是针对某一款游戏做查询,但是要查询所有的上报日志),对集群(使用的是阿里云ecs,计算能力有限)的负载过高。于是,要将原始日志表,这里简称 ods_log(2级分区表,天级,小时级),做按游戏分区处理 ods_log_game(3级区分,天,小时,游戏id),这就要用到动态分区。

动态分区

一般情况下我们使用的是静态分区,这里不做说明;
动态分区的分类有两种:
1、半自动分区(我目前使用到的是这种)
2、全分区

一、半自动分区(静态分区一定要在动态分区之前)
前提条件:开启动态区分设置:

set hive.exec.dynamic.partition=true;

一张 hive 表 ods_log_game,建表语句如下:

create table ods_log_game (
    app_name string,
    device_id string
) partitioned by (day string, hour string, app_id string) 
row format delimited fields terminated by ',';

这是一张三级分区表,day 分区和 hour 分区是静态分区,app_id 是动态分区;

在使用动态分区的时候要格外注意的是,分区字段一定是按照顺序出现在这表的末尾处,也就是说 day,hour,app_id 不可以作为这张 hive 表的真实字段的,这也是 hive 建表的规范。

动态分区字段不是按照查询出来的字段作为分区信息,而是采用查询出来的数据作为分区信息。

以 app_id 为动态分区为例:

insert overwrite table ods_log_game partition (day='$yyyy$mm$dd', hour='$hh', app_id)
select
    app_name,
    device_id,
    app_id
from ods_jp_sdk_log
where day='$yyyy$mm$dd' and hour='$hh';

其中 app_id 在进行分区时不能填写具体值,会在分区时动态指定,其实 select 中的 app_id 字段要出现在末尾的位置,这是 hive 的规范,分区字段按照顺序出现在 hive 表中,至于为什么 select 中没有 静态分区 day 和 hour 的信息,因为静态分区字段会默认加到 hive 表中,而动态分区要做特别指定。

二、全自动分区
前提条件:开启动态分区设置:

// 开启动态分区设置
set hive.exec.dynamic.partition=true;
// 这个属性默认是strict,即限制模式,strict是避免全分区字段是动态的,必须至少一个分区字段是指定有值即静态的,且必须放在最前面。设置为nonstrict之后所有的分区都可以是动态的了。
set hive.exec.dynamic.partition.mode=nonstrict;

和半自动分区类似,只不过没有静态分区,不做讨论。