我知道两者都是在表中的列上执行的,但是每个操作有什么不同。
8 回答
分区数据通常用于水平分布负载,这具有性能优势,并有助于以逻辑方式组织数据。示例:如果我们正在处理一个大employee
表并且经常运行带有WHERE
将结果限制在特定国家或部门的子句的查询。对于更快的查询响应 Hive 表可以PARTITIONED BY (country STRING, DEPT STRING)
。分区表改变了 Hive 构建数据存储的方式,Hive 现在将创建反映分区结构的子目录,例如
.../employees/国家=ABC/DEPT=XYZ。
如果查询限制为employee from country=ABC
,它只会扫描一个目录的内容country=ABC
。这可以显着提高查询性能,但前提是分区方案反映了公共过滤。分区功能在 Hive 中非常有用,但是,创建过多分区的设计可能会优化某些查询,但对其他重要查询不利。另一个缺点是分区过多是不必要创建的大量 Hadoop 文件和目录以及 NameNode 的开销,因为它必须将文件系统的所有元数据保存在内存中。
分桶是将数据集分解为更易于管理的部分的另一种技术。例如,假设一个表date
作为顶级分区和employee_id
二级分区导致太多的小分区。相反,如果我们对雇员表进行分桶并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
然后 hive 会将数据存储在目录层次结构中,例如
/user/hive/warehouse/mytable/y=2015/m=12/d=02
因此,分区时必须小心,因为例如,如果您按employee_id 分区并且您有数百万员工,那么您最终将在文件系统中拥有数百万个目录。术语“基数”是指一个字段可以具有的可能值的数量。例如,如果你有一个“国家”字段,世界上的国家大约有 300 个,所以基数约为 300。对于像“timestamp_ms”这样的字段,每毫秒都会改变一次,基数可能是数十亿。通常,在选择分区字段时,它不应该有很高的基数,因为您最终会在文件系统中拥有太多的目录。
另一方面,集群又名分桶将产生固定数量的文件,因为您确实指定了桶的数量。hive 将做的是获取字段,计算哈希并将记录分配给该存储桶。但是,如果您使用 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
- 00000_0
- 00001_0
- 00002_0
- ...........
- 00010_0
这里server_date=xyz是分区,000个文件是每个分区中的存储桶。存储桶是根据一些哈希函数计算的,因此name=Sandy的行将始终位于同一个存储桶中。
蜂巢分区:
分区根据表列的值将大量数据分成多个切片。
假设您要存储遍布全球 196 多个国家/地区的人们的信息,涉及约 50 亿条条目。如果您想查询来自特定国家(梵蒂冈城)的人,在没有分区的情况下,您必须扫描所有 50 亿个条目,甚至获取一个国家的数千个条目。如果您根据国家/地区对表进行分区,则可以通过仅检查一个国家/地区分区的数据来微调查询过程。Hive 分区为列值创建一个单独的目录。
优点:
- 水平分配执行负载
- 在数据量较小的分区的情况下更快地执行查询。例如,从“梵蒂冈城”获取人口返回速度非常快,而不是搜索整个世界的人口。
缺点:
- 太多小分区创建的可能性 - 太多目录。
- 对于给定分区的低容量数据有效。但是一些查询,如对大量数据的分组,仍然需要很长时间才能执行。例如,与梵蒂冈城的人口分组相比,中国的人口分组需要很长时间。在数据偏向特定分区值的情况下,分区不能解决响应问题。
蜂巢桶:
分桶将数据分解为更易于管理或相等的部分。
通过分区,您可以根据列值创建多个小分区。如果您进行分桶,您将限制存储数据的桶数。此数字是在表创建脚本期间定义的。
优点
- 由于每个分区中的数据量相等,因此 Map 端的连接会更快。
- 更快的查询响应,如分区
缺点
- 您可以在创建表期间定义存储桶的数量,但加载等量数据必须由程序员手动完成。
在进入之前Bucketing
,我们需要了解它是什么Partitioning
。让我们以下表为例。请注意,我在下面的示例中仅给出了 12 条记录,以供初学者理解。在实时场景中,您可能拥有数百万条记录。
PARTITIONING
---------------------
Partitioning
用于在查询数据时获得性能。比如上表,如果我们写下面的sql,需要扫描表中的所有记录,降低了性能,增加了开销。
select * from sales_table where product_id='P1'
为了避免全表扫描并只读取与我们相关的记录,product_id='P1'
我们可以根据列将 hive 表的文件分区(拆分为多个文件)product_id
。这样,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
------------------
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) 等。
不同之处在于分桶按列名划分文件,分区按表内的特定值划分文件
希望我正确定义了它
强烈建议在 Hive 表中使用分区,原因如下:
- 插入 Hive 表应该更快(因为它使用多个线程将数据写入分区)
- 从 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)
优点 - 在查询特定地理事务的数据时,可以更快地访问数据。缺点 - 通过在每个分区中拆分数据可以进一步改进插入/查询数据。请参阅下面的分桶选项。
带有分区和分桶的 Hive 表
注意:使用“CLUSTERED BY(Partiton_Column) 创建 hive 表 ..... 到 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)
优点 - 更快的插入。更快的查询。
缺点 - 分桶将创建更多文件。在某些特定情况下,许多小文件可能存在问题
希望这会有所帮助!
这里有很好的回应。我想简短地记住分区和存储桶之间的区别。
您通常在一个不太独特的列上进行分区。并在最独特的列上分桶。
例如,如果您考虑以国家、人名和他们的生物识别 ID 为例的世界人口。正如您所猜想的那样,国家字段将是不那么独特的列,而生物识别 ID 将是最独特的列。因此,理想情况下,您需要按国家/地区对表进行分区,并按生物识别 ID 对其进行存储。