[英]What is the difference between partitioning and bucketing a table in Hive ?
我知道两者都是在表中的列上执行但是每个操作的不同之处。
分区数据通常用于水平分配负载,这具有性能优势,并有助于以逻辑方式组织数据。 示例 :如果我们正在处理大型employee
表,并且经常使用WHERE
子句运行查询,这些子句将结果限制为特定国家或部门。 对于更快的查询响应,Hive表可以是PARTITIONED BY (country STRING, DEPT STRING)
。 分区表改变了Hive如何构建数据存储的方式,而Hive现在将创建反映分区结构的子目录
... / employees / country = ABC / DEPT = XYZ 。
如果来自country=ABC
员工的查询限制,它将仅扫描一个目录country=ABC
的内容。 这可以显着提高查询性能,但前提是分区方案反映了常见的过滤。 分区功能在Hive中非常有用,但是,创建太多分区的设计可能会优化某些查询,但对其他重要查询不利。 其他缺点是分区太多是大量的Hadoop文件和目录,这些文件和目录是不必要的,并且是NameNode的开销,因为它必须将文件系统的所有元数据保存在内存中。
Bucketing是另一种将数据集分解为更易于管理的部分的技术。 例如,假设一个表使用date
作为顶级分区而employee_id
作为二级分区导致太多小分区。 相反,如果我们对employee表进行存储并使用employee_id
作为bucketing列,则此列的值将由用户定义的数字散列到存储桶中。 具有相同employee_id
记录将始终存储在同一个存储桶中。 假设employee_id
的数量远远大于桶的数量,则每个桶将具有许多employee_id
。 创建表时,您可以指定CLUSTERED BY (employee_id) INTO XX BUCKETS;
其中XX是桶的数量。 Bucketing有几个优点。 存储桶的数量是固定的,因此不会随数据而波动。 如果employee_id
两个表进行了分块,则Hive可以创建逻辑上正确的抽样。 Bucketing还有助于进行有效的地图侧连接等。
前面的解释中缺少一些细节。 为了更好地理解分区和分段的工作原理,您应该了解数据如何存储在配置单元中。 假设你有一张桌子
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
然后,hive会将数据存储在目录层次结构中
/user/hive/warehouse/mytable/y=2015/m=12/d=02
因此,在分区时必须要小心,因为如果您通过employee_id进行分区并且您拥有数百万名员工,那么您的文件系统中最终将拥有数百万个目录。 术语“ 基数 ”是指字段可能具有的可能值的数量。 例如,如果您有一个“国家/地区”字段,那么世界上的国家/地区大约为300,因此基数为300。 对于像'timestamp_ms'这样每毫秒变化的字段,基数可能是数十亿。 通常,在选择用于分区的字段时,它不应该具有高基数,因为在文件系统中最终会有太多目录。
另一方面,群集aka bucketing将产生固定数量的文件,因为您确实指定了桶的数量。 什么配置单元将采取该字段,计算哈希值并将记录分配给该存储桶。 但是如果你使用让我们说256个桶并且你正在推销的字段具有低基数(例如,它是美国州,那么只能有50个不同的值)会发生什么? 你将有50个数据桶和206个没有数据的存储桶。
有人已经提到过分区如何大大减少您查询的数据量。 因此,在我的示例表中,如果您只想从特定日期向前查询,按年/月/日划分将大大减少IO的数量。 我认为有人还提到了bucketing如何加速与具有完全相同的bucketing的其他表的连接,所以在我的例子中,如果你在同一个employee_id上加入两个表,hive可以逐桶加入(甚至更好)如果它们已经按employee_id排序,因为它将合并已经排序的部分,这在线性时间即O(n)中有效。
因此,当字段具有高基数并且数据在桶之间均匀分布时,分段效果很好。 当分区字段的基数不太高时,分区效果最佳。
此外, 您可以使用订单(年/月/日是一个很好的示例) 对多个字段进行分区 ,而您只能在一个字段上 进行分区 。
我想我迟到了回答这个问题,但它一直在我的饲料中出现。
Navneet提供了出色的答案。 直观地添加它。
分区有助于消除数据(如果在WHERE子句中使用),其中bucketing有助于将每个分区中的数据组织成多个文件,因此同一组数据始终写在同一个存储桶中。 在列的加入方面有很多帮助。
假设您有一个包含五列的表,name,server_date,some_col3,some_col4和some_col5。 假设您已经在server_date上对表进行了分区,并在10个桶中的名称列上进行了分区,您的文件结构将如下所示。
这里server_date = xyz是分区, 000文件是每个分区中的桶。 存储桶是根据一些散列函数计算的,因此名称为Sandy的行将始终位于同一个存储桶中。
Hive分区:
分区根据表列的值将大量数据划分为多个切片。
假设您存储的信息遍布全球196个国家/地区,覆盖了大约500亿条记录。 如果你想查询来自特定国家(梵蒂冈城)的人,在没有分区的情况下,你必须扫描所有500亿条的条目,甚至可以获取一个国家的一千个条目。 如果您根据国家/地区对表进行分区,则只需检查一个国家/地区分区的数据即可微调查询过程。 Hive分区为列值创建单独的目录。
优点:
缺点:
Hive Bucketing:
Bucketing将数据分解为更易于管理或相同的部分。
通过分区,您可以根据列值创建多个小分区。 如果您要进行分组,则限制存储数据的桶数。 此数字在表创建脚本中定义。
优点
缺点
区别在于bucketing按列名划分文件,而分区将文件划分为表中的特定值
希望我正确定义它
在进入Bucketing
之前,我们需要了解Partitioning
是什么。 我们以下表为例。 请注意,我在下面的示例中仅提供了12条记录,以便初学者理解。 在实时场景中,您可能拥有数百万条记录。
PARTITIONING
---------------------
Partitioning
用于在查询数据时获得性能。 例如,在上表中,如果我们编写下面的sql,它需要扫描表中的所有记录,这会降低性能并增加开销。
select * from sales_table where product_id='P1'
为了避免全表扫描并且只读取与product_id='P1'
相关的记录,我们可以根据product_id
列将(将hive表的文件拆分)分成多个文件。 通过这个,hive表的文件将被分成两个文件,一个是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
用于克服我在分区部分提到的cons
。 当列中的重复值非常少时(例如 - 主键列),应该使用此选项。 这类似于RDBMS中主键列上的索引概念。 在我们的表中,我们可以使用Sales_Id
列进行Sales_Id
。 当我们需要查询sales_id
列时,它将非常有用。
以下是bucketing的语法。
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
桶,因此每个product_id
分为3个文件。 它在内部使用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)等。
这里有很好的回应。 我想简短地记住分区和桶之间的区别。
您通常在不太独特的列上进行分区。 并且在最独特的专栏上进行推销。
例如,如果您将具有国家/地区,人名及其生物指标ID的世界人口视为示例。 您可以猜测,国家/地区字段将是不太独特的列,生物指标ID将是最独特的列。 因此,理想情况下,您需要按国家/地区对表进行分区,并按生物指标ID对其进行分析。
由于以下原因,强烈建议在Hive表中使用分区 -
示例: -
假设输入文件(100 GB)被加载到temp-hive-table中,它包含来自不同地理位置的银行数据。
没有分区的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
这种方法的问题是 - 它将扫描您在此表上运行的任何查询的整个数据。 与使用分区和分段的其他方法相比,响应时间会很长。
带分区的Hive表
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)
优点 - 在查询特定地理位置交易的数据时,可以更快地访问数据。 缺点 - 通过在每个分区内拆分数据,可以进一步改进插入/查询数据。 请参阅下面的“暂停”选项
带分区和分区的蜂巢表
注意:创建配置表.....将“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)
优点 - 更快插入。 更快的查询。
缺点 - Bucketing将创建更多文件。 在某些特定情况下,许多小文件可能存在问题
希望这会有所帮助!!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.