在这篇文章中,我们将讨论Hive中的两个重要概念“分区和桶”。这些用于提高查询性能,理解它们很重要,以便您可以有效地应用它们。因此,让我们从分区开始。

0x00 分区

分区是Hive中一种用于增强查询性能的技术。通过将数据重组到子目录中来完成此操作。让我们通过一个例子来理解这个概念。

假设我们有一个10 GB的大文件,其中包含客户的地理数据。现在,我们要提取特定国家和特定受雇者身份的记录。为此,它将执行表扫描以读取所有行,然后仅选择满足给定谓词的那些记录。

现在,如果我们按国家对表进行分区并运行查询,它将不会扫描整个表,而只会查看该特定国家/地区的子目录。我们可以看到查询的执行计划,以验证它只查找一个过滤谓词即employeeId。它将直接查看子目录/Country=”印度”,并在该子目录中搜索员工。此技术称为分区修剪。该查询将过滤掉不需要扫描的分区,因此非常有效。同样,用于分区的列也不是create语句的一部分,但可以在查询中使用。它们称为虚拟分区列。每当我们将这些虚拟分区列用作过滤器时,查询服务的速度都比未分区表快得多,尤其是在数据量很大的情况下。

让我们看看如何创建Hive内部(管理表)和外部分区表并将数据加载到这些表中。

Hive内部表

1
2
3
4
5
6
7
8
9
10
11
12
--(1)创建分区表
Create table tbl_managed
(
employeeId STRING,
name STRING
)
Partitioned By(country STRING)
Stored as TextFile;
--(2)加载数据
Load Data Inpath '/mydata/Employee/India'
into Table tbl_managed
Partition(country='India')

Hive外部表

1
2
3
4
5
6
7
8
9
10
11
--(1)创建分区表
Create External table tbl_external
(
employeeid STRING,
name STRING
)
Partitioned By(country STRING)
Stored as TextFile;
--(2)添加数据
Alter Table tbl_external Add Partition(country='India')
Location '/mydata/Employee/India';

分区时的注意事项

  • 您用于分区的列的基数应该较低,即该列的不同值较低。原因是由于基数高,我们最终会有许多子目录或文件。由于mapper数量取决于输入大小和块大小,因此创建许多分区最终将使用许多mapper,并且在大多数情况下,这将导致资源浪费。
  • 许多分区还会发生的另一件事是,在内存中跟踪文件系统元数据的NameNode也将具有不必要的开销,因为它现在必须跟踪许多分区。
  • 当我们在外部表上创建分区时,位置是可选的。但是我们应该始终提供位置(例如root/a/b),因为以后可以将其用于与Hive metastore同步。因此,如果您提供了位置,然后添加了诸如root/a/b/country=’India’之类的子目录,那么当我们运行命令MSCK Repair Table Tablename时。它将自动添加该分区。

分区在以下情况下很有用

  • 分区数量有限
  • 所有分区均匀分布

0x02 桶

当由于分区不相等或分区数量太多而无法通过分区提高查询效率时,我们可以尝试进行分桶。桶概念基于桶列上的哈希函数。产生相同哈希的记录将始终位于同一存储桶中。

要将表划分为桶,我们使用Clustered by子句。每个桶就像目录中的文件,并且所有文件均等分布。

桶的优点

  • 在分桶表上进行Map-Side联接的速度更快,因为它们的大小相似。
  • 可以保持记录在每个存储桶中排序
  • 当数据按桶中的列排序并用于联接时,Map端联接甚至更快
  • 提供对非分桶表的有效采样
  • 使用分桶,我们始终可以定义要形成的桶数量,而在分区中却并非如此
  • 分区或不分区均可使用桶

如何创建分桶表:

1
2
Create Table t1(a INT,b STRING,c STRING)
CLUSTERED BY (b) BUCKETS 128 BUCKETS

Hive不会对加载到表中的数据强制执行分桶。创建表后,我们必须对其进行管理。有两种方法可以实现:

1
2
3
4
5
6
--(1)set mapred.reduce.tasks=64(桶数)
Insert Overwrite Table t1
Select a,b,c from table2 cluster by b
--(2) set hive.enforce.bucketing=true;
Insert Overwrite Table t1
Select a,b,c from table2

这将自动从Create Table语句中找出分桶列和桶数量。

参考文献

Partitioning and Bucketing in Hive