语言手册 DDL 存储表

这是创建和填充存储桶表的简短示例。 (有关另一个示例,请参见桶排序表。)

存储桶表的奇妙之处在于,它们比未存储桶的表具有更高的效率sampling,并且它们稍后可能会节省时间,例如 mapside 联接。但是,在写入表时,不会强制执行在创建表时指定的存储区,因此表的元数据可能会公布表的实际布局不支持的属性。显然应该避免这种情况。这是正确的做法。

First, table creation:

CREATE TABLE user_info_bucketed(user_id BIGINT, firstname STRING, lastname STRING)
COMMENT 'A bucketed copy of user_info'
PARTITIONED BY(ds STRING)
CLUSTERED BY(user_id) INTO 256 BUCKETS;

请注意,我们指定一列(user_id)作为存储分区的基础。

然后我们填充表格

set hive.enforce.bucketing = true;  -- (Note: Not needed in Hive 2.x onward)
FROM user_id
INSERT OVERWRITE TABLE user_info_bucketed
PARTITION (ds='2009-02-25')
SELECT userid, firstname, lastname WHERE ds='2009-02-25';

Version 0.x and 1.x only

命令set hive.enforce.bucketing = true;允许根据表自动选择正确数量的 reducer 并按列自动选择集群。否则,您需要将减速器的数量设置为与set mapred.reduce.tasks = 256;中的桶数相同,并在 select 中包含CLUSTER BY ...子句。

Hive 如何在存储桶中分配行?通常,存储桶编号由表达式hash_function(bucketing_column) mod num_buckets确定。 (那里也有一个'0x7FFFFFFF,但这并不重要)。 hash_function 取决于存储分区列的类型。对于 int,很容易hash_int(i) == i。例如,如果 user_id 是一个 int,并且有 10 个存储桶,则我们希望所有以 0 结尾的 user_id 都位于存储桶 1 中,所有以 1 结尾的 user_id 都位于存储桶 2 中,依此类推。对于其他数据类型,则为有点棘手。特别是,BIGINT 的哈希与 BIGINT 不同。字符串或复杂数据类型的哈希将是从该值派生的某个数字,而不是任何人类可识别的数字。例如,如果 user_id 是 STRING,则存储桶 1 中的 user_id 可能不会以 0 结尾。通常,基于哈希分布行将使您在存储桶中分布均匀。

那么,怎么可能出问题呢?只要您使用上面和set hive.enforce.bucketing = true的语法(对于 Hive 0.x 和 1.x),就应该正确地填充表。如果在插入和读取期间存储桶的列类型不同,或者您手动按与表定义不同的值进行聚类,则事情可能会出错。