Goal

顶级问题如下:

有许多以下格式的表:

  • create table T(a, b, c, ....., x) partitioned by (ds);

并且以下查询需要有效地执行:

  • select ... from T where x = 10;

“ x”的基数在 T 的每个分区中为 1000.此外,“ x”的值存在偏差。通常,大约 x 的'x'值具有很大的偏斜,而剩余的'x'值具有小的基数。另外,请注意,此 Map(具有高基数的“ x”值)可以每天更改。

上述要求可以通过以下方式解决:

Basic Partitioning

为值“ x”创建一个分区。

  • create table T(a,b,c, .......) partitioned by (ds, x);

  • Advantages

  • 现有的 Hive 就足够了。

  • Disadvantages

  • HDFS 可伸缩性:HDFS 中的文件数量增加。

    • HDFS 可伸缩性:HDFS 中的中间文件数量增加。例如,如果有 1000 个 Map 器和 1000 个分区,并且每个 Map 器每个键至少获得 1 行,我们最终将创建 100 万个中间文件。

    • Metastore 的可伸缩性:Metastore 会随着分区的数量而扩展。

List Bucketing

这里的基本思想如下:识别倾斜度高的键。每个偏斜的密钥都有一个目录,其余的密钥进入一个单独的目录。此 Map 在表或分区级别的元存储中维护,并且由 Hive 编译器用来进行 Importing 修剪。倾斜键的列表存储在表级别。 (请注意,此列表最初可以由 Client 端定期提供,最终可以在加载新分区时进行更新.)

例如,该表维护着'x'的倾斜键的列表:6、20、30、40.加载新分区时,它将创建 5 个目录(倾斜键的 4 个目录,其余所有默认目录 1 个)键)。已加载的表/分区将具有以下 Map:6,20,30,40,others。这类似于当前的哈希存储桶,其中存储桶号确定文件号。由于倾斜键不需要连续,因此倾斜键的整个列表需要存储在每个表/分区中。

当查询表格

  • 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%)。

  • 每个分区的偏斜键数量非常少。此列表存储在 metastore 中,因此在 metastore 中每个分区存储 100 万个偏斜键没有意义。

当有多个集群密钥时,可以将此方法扩展到方案。假设我们要优化表单查询

  • select ... from T where x = 10 and y = 'b';

  • 扩展上述方法。对于(x,y)的每个偏斜值,存储文件偏移量。因此,元存储库将具有以下 Map:(10,'a')-> 1,(10,'b')-> 2,(20,'c')-> 3,(others)-> 4.

可以轻松优化所有指定了聚类键的查询。但是,使用某些指定的群集键的查询:

    • select ... from T where x = 10;

    • select ... from T where y = 'b';

只能用于修剪很少的目录。是否指定聚类键的前缀并不重要。例如对于 x = 10,Hive 编译器可以修剪对应于(20,'c')的文件。对于 y ='b',可以删除与(10,'a')和(20,'c')相对应的文件。如果未指定完整密钥,则对其他人的哈希处理并没有 true 的帮助。

在以下情况下,此方法无法扩展:

  • 倾斜键的数量非常大。这为 metastore 可伸缩性带来了问题。

  • 在大多数情况下,集群键的数量不止一个,并且在查询中,未指定所有集群键。

歪斜表与列表存储区表

  • 歪斜表是具有歪斜信息的表。

    • List Bucketing Table *是倾斜的表格。此外,它还告诉 Hive 在偏斜表上使用列表存储桶功能:为偏斜值创建子目录。

可以将普通的倾斜表用于倾斜联接等。(请参见偏斜连接优化设计文档。)如果不使用列表存储功能,则无需将其定义为列表存储表。

清单桶验证

主要由于其子目录的性质,列表存储不能与某些功能共存。

DDL

如果列表存储表与以下文件共存,则将引发编译错误

  • 常规存储区(由,tablesample 等组成)

  • external table

  • " load data ... "

  • CTAS(选择时创建表)查询

DML

如果列表存储表与以下文件共存,则将引发编译错误

  • " insert into "

  • 常规存储区(由,tablesample 等组成)

  • external table

  • 非 RCfile 由于合并

  • non-partitioned table

分区值不应与默认列表存储目录名称相同。

Alter Table 串联

如果列表存储表与以下文件共存,则将引发编译错误

  • non-RCfile

  • 变更表的外部表

Hive Enhancements

Hive 需要扩展以支持以下内容:

Create Table

CREATE TABLE <T> (SCHEMA) SKEWED BY (keys) ON ('c1', 'c2') [STORED AS DIRECTORIES];

该表将是一个倾斜的表。将为所有分区创建倾斜的信息。

For example:

  • 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;

“按目录存储”是一个可选参数。它告诉 Hive,它不仅是歪斜的表,而且列表存储功能也应适用:为歪斜的值创建子目录。

Alter Table

倾斜的修改表

ALTER TABLE <T> (SCHEMA) SKEWED BY  (keys) ON ('c1', 'c2') [STORED AS DIRECTORIES];

仅在表级别而非分区级别支持以上功能。

It will

  • 将表从非倾斜表转换为倾斜表,否则

  • 更改偏斜表的偏斜列名和/或偏斜值。

会影响

  • 在 alter 语句之后创建的分区

  • 但不在 alter 语句之前创建的分区。

Alter Table 不倾斜

ALTER TABLE <T> (SCHEMA) NOT SKEWED;

以上将

  • 关闭表格中的“倾斜”功能

  • 使表格不倾斜

  • 请关闭“列表存储区”功能,因为列表存储区表也是倾斜的表。

会影响

  • 在 alter 语句之后创建的分区

  • 但不在 alter 语句之前创建的分区。

更改表未存储为目录

ALTER TABLE <T> (SCHEMA) NOT STORED AS DIRECTORIES;

以上将

  • 关闭“列表存储”

  • 不要从表中关闭“倾斜”功能,因为“倾斜”表可以是没有列表存储的普通“倾斜”表。

更改表设置的偏斜位置

ALTER TABLE <T> (SCHEMA) SET SKEWED LOCATION (key1="loc1", key2="loc2");

上面将更改列表存储区位置图。

Design

加载此类表时,最好为每个倾斜的键创建一个子目录。可以使用类似于动态分区的基础结构。

Alter table <T> partition <P> concatenate;需要更改以合并每个目录中的文件。

Implementation

Version information

列表存储区已在 Hive 0.10.0 和 0.11.0 中添加。

HIVE-3026是列表存储功能的 JIRA 根票证。它具有指向其他 JIRA 票证的链接,这些票证在 Hive 中实现列表存储,包括:

  • HIVE-3554:配置单元列表存储区-查询逻辑(0.10.0 版)

  • HIVE-3649:配置单元列表存储区-增强 DDL 以指定列表存储区表(版本 0.10.0)

  • HIVE-3072:配置单元列表存储区-DDL 支持(0.10.0 版)

  • HIVE-3073:配置单元列表存储区-DML 支持(0.11.0 版)

有关更多信息,请参见DDL 文档中的歪斜表