在Hive中(ORC文件格式下)排序表

4

我遇到了一些困难,无法确定在Hive表中利用已排序的数据。(使用ORC文件格式)

我知道我们可以通过在创建DDL中声明 DISTRIBUTE BY 子句来影响从Hive表中读取数据的方式。

CREATE TABLE trades
(
    trade_id INT,
    name STRING,
    contract_type STRING,
    ts INT
)
PARTITIONED BY (dt STRING)
CLUSTERED BY (trade_id) SORTED BY (trade_id, time) INTO 8 BUCKETS
STORED AS ORC;

这意味着每次查询该表时,数据将按照trade_id在各个mapper之间分布,然后进行排序。
我的问题是:
我不想把数据分成N个文件(桶),因为数据量不大,我希望保留小文件。
但是,我确实想利用排序插入。
INSERT OVERWRITE TABLE trades
PARTITION (dt)
SELECT trade_id, name, contract_type, ts, dt
FROM raw_trades
DISTRIBUTE BY trade_id
SORT BY trade_id;

我是否真的需要在create DLL语句中使用CLUSTERED/SORT?或者Hive/ORC知道如何利用插入过程已经确保数据排序的事实?

做类似以下的事情是否有意义:

CLUSTERED BY (trade_id) SORTED BY (trade_id, time) INTO 1 BUCKETS

1
你在问题开头谈到了DISTRIBUTE BY,但显然是指CLUSTERED BY。 - FurryMachine
2
回答你的问题,据我所知,这是优化具有预排序数据信息的Hive查询的唯一方法。在不创建聚集表的情况下对数据进行排序也可能会提高原始ORC性能,例如压缩或在排序列上查找(因为ORC每个文件保留最小/最大统计信息)。 但是,如果您希望Hive Optimizer利用排序信息,则需要一个分桶表。如果表很小,只有1个桶可能是有意义的,但如果表很小,为什么还需要优化呢? - FurryMachine
1个回答

4

桶表是一种过时的概念。

在表DDL中不需要写CLUSTERED BY。

在加载表时,使用distribute by partition key来减轻Reducer的压力,特别是在写入ORC时,它需要中间缓冲区来构建ORC,如果每个Reducer加载了许多分区,可能会导致OOM异常。

当表很大时,可以使用bytes.per.reducer限制最大文件大小,例如:

set hive.exec.reducers.bytes.per.reducer=67108864;--or even less

如果数据量更大,将启动更多的reducers,并创建更多的文件。这比加载固定数量的桶更灵活。

这也更有效,因为对于小表,您不需要创建更小的桶。

ORC具有内部索引和布隆过滤器。 通过应用排序,您可以提高索引和布隆过滤器的效率,因为所有类似的数据都将存储在一起。此外,这可以根据您的数据熵来提高压缩率。

如果按分区键分布不足以解决数据倾斜问题,且数据量较大,则可以通过随机方式进行进一步分发。如果数据均匀分布,则最好按列进行分发。如果数据不均匀,则应通过随机方式进行分发,以避免单个长时间运行的reducer问题。

最后,您的插入语句可能如下所示:

set hive.exec.reducers.bytes.per.reducer=33554432; --32Mb per reducer

INSERT OVERWRITE TABLE trades PARTITION (dt)
SELECT trade_id, name, contract_type, ts, dt
FROM raw_trades
DISTRIBUTE BY dt,                    --partition key is a must for big data
              trade_id,              --some other key if the data is too big and key is
                                     --evenly distributed (no skew)   
              FLOOR(RAND()*100.0)%20 --random to distribute additionally on 20 equal parts 

SORT BY contract_type; --sort data if you want filtering by this key 
                       --to work better using internal index

不要在表DDL中使用CLUSTERED BY,因为使用DISTRIBUTE BY、ORC w indexes和bloom filters + SORT插入时可以以更加灵活的方式实现相同的功能。
分发+排序可以将ORC文件的大小减少3倍或4倍。类似的数据可以更好地压缩,并使内部索引更有效。
也请阅读此文:https://dev59.com/U7Lma4cB1Zd3GeqPg9IG#55375261 关于排序的答案:https://dev59.com/L6bja4cB1Zd3GeqPn-2H#47416027 唯一可以在表DDL中使用CLUSTER BY的情况是当您连接两个大表时,这些表可以通过完全相同数量的bucket进行分桶,以便能够使用sort-merge-bucket-map-join,但实际上,您很少能够像这样将两个大表进行分桶。只有一个bucket是没有意义的,因为对于小表,您可以使用map-join,在插入期间对数据进行排序以减少压缩数据的大小。

@leftjoin-- 如果我们需要在某个键上连接两个表,那么使用 distribute by 加载这两个表将与 bucketing 的工作方式相同吗?另外,我们是否需要在两个表中都使用 RAND 函数平均分配文件? - vikrant rana
1
如果文件是ORC格式,那么它们将具有内部索引和高效压缩的数据。启用ppd后,它将完美地工作。在写入文件时进行均等分布可以帮助避免因不平衡而导致的缓慢运行的reducer。在读取ORC文件时,它们会被分割,如果它们大小不同也没有问题。 - leftjoin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接