Hive中的分桶,是对指定的列值取哈希与指定的分桶数取模,根据余数确定数据所在的分桶,适用于抽样和map-join。
- 创建分桶表
create table bucket_table_name [columns]
clustered by (bucket_column_name) [SORTED BY (col_name [ASC|DESC], ...)]
into num_buckets buckets
注意:sort by不是全局排序,其在数据进入reducer前完成排序。因此,如果用sort by进行排序,并且设置mapred.reduce.tasks>1,则sort by只保证每个reducer的输出有序,不保证全局有序。
- 分桶数的确定
网上很多文章都说明了如何创建分桶,以及分桶的好处,但没有关于如何确定分桶数的相关说明(至少我没找到)。
下面我结合自己的理解,总结下关于分桶数如何确定。
首先,需要知道与分区字段的值对应一个目录不同的是,分桶的个数对应数据文件的个数,也就是说如果指定了4个分桶,
则数据文件对应4个子文件。
其次,如果支持分桶,需要设定 Hive.enforce.bucketing=true。该配置项的值默认是false,设置成true后,MR运行时会根据
bucket的个数自动分配Reduce Task的个数。(当然,用户也可以通过mapred.reduce.tasks自己设定reduce task的数量,但是
分桶时不建议使用)。
基于以上信息,假定分桶字段的数据是均匀的(数据倾斜不在本次讨论范围内),则可以根据表中数据量的大小来确定分桶个数,即在保证每个文件大小不小于128M(HDFS中存储数据的Block的大小)的前提下,可以适当增加分桶数。增加分桶数,会使得reduce task的数量随之增加,有利于提高并行度。
但是由于集群硬件性能,以及集群空闲资源等因素的影响,reduce task的并行会受到影响,所以分桶数并不是越多越好。
即便是资源充足,由于一个桶对应一个文件,桶越多文件就越多,每个文件的大小就越小,当小于Block大小的时候(默认128M),就会造成小文件过多的情况(关于小文件的定义各有不同,我理解的是小于Block大小的就是小文件),hdfs并不适合存储小文件。因此分桶还有考虑最终生成的文件的大小。
- 分桶表加载数据
分桶表加载数据一般使用insert into的方式,不推荐使用load data的方式。因为load data的数据并不会自动分桶,如果要使用load data 的方式加载数据,必须先手动对数据进行分桶。