Hive是一个建立在Hadoop之上的数据仓库工具,被沃尔玛、TikTok和AT&T等公司广泛使用。对于数据工程师来说,学习和掌握Hive是一项重要的技术。Hive使用一种称为HQL(Hive Query Language)的声明式语言,与SQL非常相似,这使得具有SQL背景的数据库工程师和新手能够处理数据工程任务。在内部,HQL作为map-reduce代码的抽象层,许多开发者发现编写和调试map-reduce代码较为困难。由于用HQL替代了map-reduce代码,开发时间大幅减少,这被视为一个主要优势。所有数据都以结构化格式存储,看起来和感觉就像一个普通的MySQL数据库,这简化了开发者的工作。正如前面提到的,Hive是一个数据仓库,仅支持批量处理。Hive不支持实时数据处理和跟踪的原因是其非常高的延迟和庞大的数据量。此外,Hive在小数据集上的表现也非常差。
分区是提高Hive性能的流行策略之一。本质上,分区只是将数据存储在多个文件夹中的一种正式方式,通过某些特定标准将它们分开,而不是将所有内容存储在一个单一的文件夹中。由于数据被分开,查询性能得到了极大的提升,因为记录数量大幅减少。这也有助于降低查询的计算复杂性。例如,假设有一个包含1000个食品项目及其相关信息的Hive表,其中一列名为“素食”,指定食品项目是否为素食。假设有300个素食食品项目和700个非素食食品项目。另外,假设对于素食食品项目,其值为“1”,否则为“0”。如果进行一个特定于素食食品项目的查询,Hive服务器必须扫描Hive表中的所有1000条记录并返回查询结果。现在,假设使用“素食”列对表进行了分区。记录将被分成两个文件夹,一个包含素食食品项目,另一个包含非素食食品项目,如果尝试运行相同的查询,Hive服务器只需要扫描包含素食食品项目的文件夹,因此被评估的记录总数大幅减少,即300条记录。希望比较分区前后扫描的记录数量能更好地说明它如何帮助提高性能,同时降低查询的计算复杂性。此外,分区可以扩展到任何级别,如层次结构。为了更好地理解这一点,在上述例子中,假设有一个字段指定了准备食品项目时使用的肉类类型,如“红肉”、“海鲜”、“家禽”等。现在也可以进一步使用这个字段对表进行分区。如果这样做,将在非素食文件夹中创建名为“红肉”、“海鲜”等的文件夹。因此,层次结构可以不断扩展,可以对分区进行精细控制以提高性能。
Hive支持静态分区和动态分区。在动态分区中,分区会自动创建,Hive会将数据分开并加载到各自的目录中。在静态分区中,分区应该由手动创建,相应的数据也应该由加载。当分区数量较大时使用动态分区,但在加载时间方面,静态分区表现更好。现在知道了什么是分区,让看看如何在Hive中使用HQL执行动态和静态分区的一些查询。
$ hive.exec.dynamic.partition=true;
$ hive.exec.max.dynamic.partitions=1000;
$ set hive.mapred.mode='strict';
$ set hive.mapred.mode='nonstrict';
$ create table {table_name}({column_name} {data_type}, {column_name} {data_type}, {column_name} {data_type}) partitioned by ({partition_column_name} {data_type}, {partition_column_name} {data_type}, {partition_column_name} {data_type});
$ show partitions {table_name};
$ hive.exec.dynamic.partition=false;
$ create table {table_name} ({column_name} {data_type}, {column_name} {data_type}, {column_name} {data_type}) partitioned by ({partition_column_name} {data_type}, {partition_column_name} {data_type}, {partition_column_name} {data_type});
$ insert into {table_name} partition ({partition_col}='condition_1', {partition_col}='condition_2', {partition_col}='condition_3') select {column_name}, {column_name}, {column_name} from {unpartitioned_table_name} where (({partition_col}='condition_1') and ({partition_col}='condition_2') and ({partition_col}='condition_3'));
create table {table_name} ({column_name} {data_type}, {column_name} {data_type}, {column_name} {data_type}) clustered by ({bucketing_column_name}) into {n} buckets;