原文连接:https://cwiki.apache.org/confluence/display/Hive/ListBucketing
- 场景分析
- 假设我们创建的分区表的结构如:create table T(a, b, c, ....., x) partitioned by (ds);
- 但是需要高效地执行查询:select ... from T where x = 10; (没有用到分区而是用到其中一个列,x列是存在数据倾斜的列)这样查询的话,会出现数据倾斜现象,x列中大概有10个值具有非常大的倾斜,其余的值是比较小的数,运行的时候,任务会出现倾斜现象
- 解决方案
- 方案一:将x列添加到分区中 create table T(a,b,c, .......) partitioned by (ds, x);
- 优缺点:
- 优点:分区的添加让数据定位更加快捷
- 缺点:新增一个字段作为分区字段,让分区更加详细了,但是HDFS的文件数量增加;HDFS中的中间文件数量增加;Metastore元数据表将随着分区的数量增加而增加,带来一定的压力
- 方案二:倾斜表(List Bucketing)
- 定义
- 倾斜表可以识别具有倾斜严重的key,每个倾斜严重的key都有一个单独的目录,其余的键都进入另外一个others的目录
- 此映射在元存储中的表或分区级别里维护,并由配置单元编译器用于执行输入修剪
- 倾斜键的列表存储在表级别(该列表最初可以由客户机定期提供,最终可以在加载新分区时更新)
- 例子说明:
- 一个表维护了“x”的倾斜key列表:6, 20, 30, 40,当加载一个新分区时,它将创建5个目录(4个倾斜key目录+1个所有剩余键的默认目录),加载的表/分区将具有以下映射:6、20、30、40、others
- 这与当前的hash bucketing类似,bucket编号决定文件编号。因为倾斜键不需要是连续的,所以倾斜键的整个列表需要存储在每个表/分区中。
- 当执行 select ... from T where ds = '2012-04-15' and x = 30; Hive编译器会使用对应x=30的目录执行map reduce作业
- 当执行 select ... from T where ds = '2012-04-15' and x = 50;Hive编译器会使用对应x=others的目录执行map reduce作业
- 使用场景:
- 每个分区的倾斜键占总数据的很大一部分。在上面的示例中,如果倾斜键(6、20、30和40)只占用数据的一小部分(比如20%),那么x=50形式的查询仍然需要扫描剩余的数据(80%)
- 每个分区的倾斜键的数量非常少。数量过大,会给元数据存储带来压力
- 扩展优化:以扩展到多个key组合的情况
- 假设我们要优化的查询 select ... from T where x = 10 and y = 'b'; 对于组合键(x,y)的每个倾斜值,会存储文件偏移量。因此,元存储将具有如下映射:(10,'a')->1,(10,'b')->2,(20,'c')->3,(others)->4
- 如果多个key都同时使用到的话,那么可以会快定位到文件目录所在,但是如果只是使用某个key的话,例如 select ... from T where x = 10; 或者 select ... from T where y = 'b'; 这样的话,只能过滤掉一些不符合条件的目录(是否是组合键的前缀没有影响,可能内部会有优化?)
- 当x=10的条件下,编译器可以减少对(20,'c')文件目录的扫描
- 对于y='b',可以减少对(10,'a')和(20,'c')的文件目录的扫描,但是对于其他(others)是没有帮助的
- 如果在查询中,没有指定对应的倾斜key,那么就是扫描所有的数据进行过滤
- Skewed Table vs. List Bucketing Table
- Skewed Table是具有倾斜信息的表(普通的表,但是数据会倾斜)
- List Bucketing Table是一个倾斜表,它会为倾斜值创建子目录
- 操作验证
- 由于倾斜表的子目录性质,所以不能和某些特性共存
- DDL:list bucketing table和以下共存会编译报错
- 正常的分桶表 (clustered by, tablesample, etc.)
- 外部表
- 使用“load data …”加载数据
- 使用 CTAS (Create Table As Select) 语句
- DML:list bucketing table和以下共存会编译报错
- 使用“insert into”插入数据
- 正常的分桶表(clustered by, tablesample, etc.)
- 外部表(external table)
- non-RCfile due to merge
- non-partitioned table
- 分区值不应与默认的列表list bucketing table目录名相同
- 修改表连接(Alter Table Concatenate):list bucketing table和以下共存会编译报错
- non-RCfile
- external table for alter table
- 操作:
- 创建表 Create Table
- 创建一个倾斜表,为所有分区创建倾斜信息 CREATE TABLE <T> (SCHEMA) SKEWED BY (keys) ON ('c1', 'c2') [STORED AS DIRECTORIES];
- 例如:
- create table T (c1 string, c2 string) skewed by (c1) on ('x1') stored as directories;
- create table T (c1 string, c2 string, c3 string) skewed by (c1, c2) on (('x1', 'x2'), ('y1', 'y2')) stored as directories;
- 注:“STORED AS DIRECTORIES”是可选参数。它告诉Hive它不仅是一个倾斜表,而且是个list bucketing表:为倾斜的值创建子目录
- 修改表 Alter Table
- 修改普通表表为倾斜表(只支持表级别,不支持分区表)ALTER TABLE <T> (SCHEMA) SKEWED BY (keys) ON ('c1', 'c2') [STORED AS DIRECTORIES];
- 将表从非倾斜表转换为倾斜表
- 更改倾斜表的列名或倾斜值
- 表转换:将倾斜表转换为普通表 ALTER TABLE <T> (SCHEMA) NOT SKEWED;
- 关掉表的倾斜功能,使得表为普通表非倾斜表
- 关闭"list bucketing" 的功能
- 修改倾斜表不额外创建分区目录 ALTER TABLE <T> (SCHEMA) NOT STORED AS DIRECTORIES;
- 关闭"list bucketing" 的功能
- not turn off the "skewed" feature from table since a "skewed" table can be a normal "skewed" table without list bucketing.
- 更改倾斜表的倾斜key的location位置 ALTER TABLE <T> (SCHEMA) SET SKEWED LOCATION (key1="loc1", key2="loc2");
- 设计
- 在加载这样的表时,最好为每个倾斜键创建一个子目录。可以使用类似于动态分区的基础结构。
- Alter table<T>partition<P>concatenate;
- 需要更改以合并每个目录的文件。
本文仅作为笔记使用,方便以后查询,可读性可能不是很好,记录信息大部分来自网上
浙公网安备 33010602011771号