Answers:
分区数据通常用于水平分布负载,这具有性能优势,并有助于以逻辑方式组织数据。例如:如果我们要处理一个大employee
表,并且经常运行带有WHERE
将结果限制在特定国家或地区的子句的查询。为了更快的查询响应,可以使用Hive表PARTITIONED BY (country STRING, DEPT STRING)
。分区表更改了Hive构造数据存储的方式,Hive现在将创建反映分区结构的子目录,例如
... /员工/ 国家 / 地区= ABC / DEPT = XYZ。
如果查询来自雇员的限制country=ABC
,它将仅扫描一个目录的内容country=ABC
。仅当分区方案反映通用筛选时,这才能大大提高查询性能。分区功能在Hive中非常有用,但是,创建过多分区的设计可能会优化某些查询,但会对其他重要查询不利。另一个缺点是分区过多,这是不必要地创建了大量的Hadoop文件和目录,并给NameNode带来了开销,因为它必须将文件系统的所有元数据都保留在内存中。
存储桶是将数据集分解为更易于管理的部分的另一种技术。例如,假设一个表date
用作顶级分区和employee_id
第二级分区会导致太多的小分区。相反,如果我们对employee表进行存储并employee_id
用作存储列,则该列的值将由用户定义的数字散列到存储桶中。具有相同记录的记录employee_id
将始终存储在同一存储桶中。假设的数量employee_id
远大于存储桶的数量,则每个存储桶将具有许多employee_id
。创建表时,您可以指定如下CLUSTERED BY (employee_id) INTO XX BUCKETS;
其中XX是存储桶数。桶装有几个优点。桶的数量是固定的,因此它不会随数据波动。如果两个表由进行存储employee_id
,则Hive可以创建逻辑上正确的采样。桶也有助于进行有效的地图侧联接等。
前面的解释中缺少一些细节。为了更好地了解分区和存储的工作原理,您应该查看数据在hive中的存储方式。假设您有一张桌子
CREATE TABLE mytable (
name string,
city string,
employee_id int )
PARTITIONED BY (year STRING, month STRING, day STRING)
CLUSTERED BY (employee_id) INTO 256 BUCKETS
然后配置单元会将数据存储在目录层次结构中,例如
/user/hive/warehouse/mytable/y=2015/m=12/d=02
因此,在分区时必须格外小心,因为例如,如果按employee_id进行分区,并且拥有数百万个员工,那么文件系统中最终将拥有数百万个目录。术语“ 基数 ”是指字段可以具有的可能值的数量。例如,如果您有一个“国家”字段,则世界上的国家大约为300个,因此基数约为300。对于“ timestamp_ms”这样的字段(每毫秒更改一次),基数可以达到数十亿。通常,在选择要分区的字段时,它的基数不应该很高,因为文件系统中的目录太多了。
另一方面,由于也指定了存储桶的数量,因此集群化也称为存储桶将具有固定数量的文件。配置单元将执行的操作是获取字段,计算哈希值并将记录分配给该存储桶。但是,如果您使用256个存储桶,而您存储的字段的基数较低(例如,这是美国州,则只能有50个不同的值),会发生什么?您将拥有50个带数据的存储桶,以及206个无数据的存储桶。
有人已经提到分区如何可以极大地减少您查询的数据量。因此,在我的示例表中,如果只想从某个日期开始查询,按年/月/日进行分区将大大减少IO数量。我认为有人还提到了存储桶如何加快与具有完全相同存储桶的其他表的联接,因此在我的示例中,如果要在同一个employee_id上连接两个表,hive可以逐桶进行联接存储桶(甚至更好)如果它们已经由employee_id进行了排序,因为它将合并已经排序的部分,则该工作在线性时间中也称为O(n))。
因此,当字段具有高基数并且数据在存储桶之间均匀分布时,存储桶可以很好地工作。当分区字段的基数不太高时,分区效果最好。
另外,您可以按顺序在多个字段上进行分区(年/月/日是一个很好的示例),而只能在一个字段上进行存储。
我想我回答这个问题很晚,但是它一直在我的提要中出现。
Navneet提供了很好的答案。视觉上添加。
分区有助于消除数据(如果在WHERE子句中使用),而分区则有助于将每个分区中的数据组织到多个文件中,因此同一组数据始终写入同一存储桶中。在连接列方面有很大帮助。
假设您有一个包含五列的表,它们分别是名称,server_date,some_col3,some_col4和some_col5。假设您已经在server_date上对表进行了分区,并在10个存储桶中的name列上进行了存储,您的文件结构将如下所示。
这里server_date = xyz是分区,000个文件是每个分区中的存储桶。存储桶是基于某些哈希函数计算的,因此name = Sandy的行将始终位于同一存储桶中。
配置单元分区:
分区基于表列的值将大量数据分为多个切片。
假设您要存储遍布196个以上国家/地区的人的信息,这些人的条目总数约为50亿。如果要查询来自特定国家(梵蒂冈)的人员,在没有分区的情况下,您必须扫描所有50亿条目,甚至要获取一个国家的数千条目。如果按国家对表进行分区,则只需检查一个国家分区的数据就可以优化查询过程。配置单元分区为列值创建一个单独的目录。
优点:
缺点:
蜂箱存储:
存储桶将数据分解为更易于管理或相等的部分。
使用分区时,可能会基于列值创建多个小分区。如果要进行存储分区,则将限制存储数据的存储分区的数量。此编号是在表创建脚本期间定义的。
优点
缺点
在开始之前Bucketing
,我们需要了解什么Partitioning
。让我们以下表为例。请注意,在下面的示例中,我仅给出了12条记录以供初学者理解。在实时方案中,您可能有数百万条记录。
分区
---------------------
Partitioning
用于在查询数据时获得性能。例如,在上表中,如果我们编写以下sql,则需要扫描表中的所有记录,这会降低性能并增加开销。
select * from sales_table where product_id='P1'
为了避免全表扫描并仅读取与之相关的记录,product_id='P1'
我们可以基于product_id
列将分区(拆分配置单元表的文件)划分为多个文件。这样,配置单元表的文件将被拆分为两个文件,一个为product_id='P1'
,另一个为product_id='P2'
。现在,当我们执行上述查询时,它将仅扫描product_id='P1'
文件。
../hive/warehouse/sales_table/product_id=P1
../hive/warehouse/sales_table/product_id=P2
下面给出了创建分区的语法。请注意,product_id
在以下语法中,我们不应将列定义与未分区的列一起使用。这只能在partitioned by
子句中。
create table sales_table(sales_id int,trans_date date, amount int)
partitioned by (product_id varchar(10))
缺点:分区时我们应该非常小心。也就是说,不应将其用于重复值数量很少的列(尤其是主键列),因为它会增加分区文件的数量并增加的开销Name node
。
BUCKETING
------------------
Bucketing
用于克服cons
我在分区一节中提到的内容。当一列(例如-主键列)中的重复值很少时,应使用此选项。这类似于RDBMS中主键列上的索引的概念。在我们的表中,我们可以将Sales_Id
列用于存储。当我们需要查询sales_id
列时,它将很有用。
以下是存储分区的语法。
create table sales_table(sales_id int,trans_date date, amount int)
partitioned by (product_id varchar(10)) Clustered by(Sales_Id) into 3 buckets
在这里,我们将进一步在分区顶部将数据分成几个文件。
由于我们已指定3
存储桶,因此每个存储桶都分为3个文件product_id
。它在内部用于modulo operator
确定每个sales_id
存储在哪个存储桶中。例如,对于product_id='P1'
,sales_id=1
将存储在000001_0文件中(即1%3 = 1),sales_id=2
将存储在000002_0文件中(即2%3 = 2),sales_id=3
将存储在000000_0文件中(即3% 3 = 0)等。
hashCode()
字符串的Java 作为哈希函数?程序员可以选择哈希函数吗?
出于以下原因,强烈建议在Hive表中使用分区:
例子:-
假设输入文件(100 GB)已加载到temp-hive表中,并且其中包含来自不同地理位置的银行数据。
没有分区的配置单元表
Insert into Hive table Select * from temp-hive-table
/hive-table-path/part-00000-1 (part size ~ hdfs block size)
/hive-table-path/part-00000-2
....
/hive-table-path/part-00000-n
这种方法的问题是-它将扫描整个数据以查找您在此表上运行的任何查询。与使用分区和存储桶的其他方法相比,响应时间会很高。
带有分区的配置单元表
Insert into Hive table partition(country) Select * from temp-hive-table
/hive-table-path/country=US/part-00000-1 (file size ~ 10 GB)
/hive-table-path/country=Canada/part-00000-2 (file size ~ 20 GB)
....
/hive-table-path/country=UK/part-00000-n (file size ~ 5 GB)
优点-在查询特定地理位置交易的数据时,可以更快地访问数据。缺点-通过在每个分区内分割数据,可以进一步改善插入/查询数据。请参阅下面的存储桶选项。
带有分区和存储分区的Hive表
注意:使用“ CLUSTERED BY(Partiton_Column)”将配置单元表创建为5个存储桶...
Insert into Hive table partition(country) Select * from temp-hive-table
/hive-table-path/country=US/part-00000-1 (file size ~ 2 GB)
/hive-table-path/country=US/part-00000-2 (file size ~ 2 GB)
/hive-table-path/country=US/part-00000-3 (file size ~ 2 GB)
/hive-table-path/country=US/part-00000-4 (file size ~ 2 GB)
/hive-table-path/country=US/part-00000-5 (file size ~ 2 GB)
/hive-table-path/country=Canada/part-00000-1 (file size ~ 4 GB)
/hive-table-path/country=Canada/part-00000-2 (file size ~ 4 GB)
/hive-table-path/country=Canada/part-00000-3 (file size ~ 4 GB)
/hive-table-path/country=Canada/part-00000-4 (file size ~ 4 GB)
/hive-table-path/country=Canada/part-00000-5 (file size ~ 4 GB)
....
/hive-table-path/country=UK/part-00000-1 (file size ~ 1 GB)
/hive-table-path/country=UK/part-00000-2 (file size ~ 1 GB)
/hive-table-path/country=UK/part-00000-3 (file size ~ 1 GB)
/hive-table-path/country=UK/part-00000-4 (file size ~ 1 GB)
/hive-table-path/country=UK/part-00000-5 (file size ~ 1 GB)
优点-插入速度更快。更快的查询。
缺点-桶将创建更多文件。在某些特定情况下,许多小文件可能存在问题
希望这会有所帮助!