我知道两个操作都是在表中对列执行的,但是每个操作有什么不同。
employee
表格,并且经常运行带有WHERE
子句的查询将结果限制在特定的国家或部门。为了更快的查询响应,Hive表可以通过 PARTITIONED BY (country STRING, DEPT STRING)
进行分区。对表进行分区会改变Hive的数据存储结构,Hive现在会创建反映分区结构的子目录,如:
.../employees/country=ABC/DEPT=XYZ。
如果查询限制为从country=ABC
的员工,则仅会扫描一个目录country=ABC
的内容。这可以极大地提高查询性能,但前提是分区方案反映出常见的筛选方式。分区功能在Hive中非常有用,但是,创建太多的分区的设计可能会优化一些查询,但对其他重要查询却有害无益。另一个缺点是如果拥有太多的分区,将会创建大量的Hadoop文件和不必要的目录,对NameNode造成额外的负担,因为它必须将文件系统的所有元数据保存在内存中。
分桶技术是将数据集分解为更易处理的部分的另一种技术。例如,假设一个表使用日期
作为顶级分区,以员工ID
作为第二级分区会导致太多的小分区。相反,如果我们对员工表进行分桶,并使用员工ID
作为分桶列,该列的值将被用户定义的数字散列到桶中。具有相同员工ID
的记录始终存储在同一个桶中。假设员工ID
的数量远大于桶的数量,则每个桶将有许多员工ID
。创建表时,您可以指定类似于CLUSTERED BY (employee_id) INTO XX BUCKETS;
的语句,其中XX是桶的数量。分桶具有几个优点。桶的数量是固定的,因此不会随数据波动。 如果两个表都按员工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进行分区并且有数百万名员工,你最终会在文件系统中拥有数百万个目录。在涉及到分桶(Bucketing)
之前,我们需要了解什么是分区(Partitioning)
。让我们以下面的表格为例进行说明。请注意,我在下面的示例中仅提供了12条记录,以方便初学者理解。在实时情况下,您可能会有数百万条记录。
分区
---------------------
分区
用于在查询数据时获得性能优化。例如,在上面的表格中,如果我们编写以下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)
用于克服我在分区部分提到的缺点
。当一列中有非常少量的重复值(例如主键列)时,应使用此方法。这类似于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
个桶,因此每个product_id
会被拆分成3个文件。它内部使用取模运算符
来确定每个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()
作为哈希函数?程序员能否选择哈希函数? - Don Smith我认为我回答这个问题有些晚了,但它一直出现在我的订阅中。
Navneet给出了很好的答案。从视觉上添加一些内容。
如果在WHERE子句中使用,分区可以帮助消除数据,而桶可以帮助将每个分区中的数据组织成多个文件,以便相同的数据集始终写入同一桶中。在列连接中非常有帮助。
假设您有一个具有五个列的表,名称为name,server_date,some_col3,some_col4和some_col5。假设您已经对server_date进行了分区,并在10个桶上对name列进行了划分,那么您的文件结构将如下所示。
这里的server_date=xyz是分区,000文件是每个分区中的桶。桶是基于某些哈希函数计算的,因此具有name=Sandy的行将始终进入同一个桶中。
希望我定义得正确。
在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
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)
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)
优点 - 插入速度更快。查询速度更快。
缺点 - 分桶会创建更多的文件。在某些特定情况下,可能会出现许多小文件的问题。
希望这能帮到您!!
Id1 id2 value
eg. 1 2 3
1 2 4
1 2 5