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

Sorted Table in Hive (ORC file format)

我在确保在 Hive table 中利用排序数据时遇到了一些困难。 (使用 ORC 文件格式)

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

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;

这意味着每次我对此 table 进行查询时,数据将通过 trade_id 在各种映射器之间分发,然后进行排序。

我的问题是:

我不希望将数据拆分为 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;

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

做这样的事情是否有意义:

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

分桶 table 是一个过时的概念。

您不需要在 table DDL 中编写 CLUSTERED BY。

加载table时使用distribute by partition key减轻reducer的压力,尤其是在编写ORC时,需要中间缓冲区来构建ORC,如果每个reducer加载很多分区,可能会导致OOM异常。

当 table 较大时,您可以使用 bytes.per.reducer 限制最大文件大小,如下所示:

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

如果你有更多的数据,就会启动更多的reducer,创建更多的文件。这比加载固定数量的桶更灵活。

这也会更好地工作,因为对于小的 table,您不需要创建更小的桶。

ORC 有内部索引和布隆过滤器。 Applying SORT you can improve index and bloom filters efficiency because all similar data will be stored together. Also this can improve compression depending on your data enthropy.

如果由于数据倾斜且数据量大,分区键分配不够,您可以另外进行随机分配。如果数据分布均匀,最好按列分布。如果不是,则随机分配以避免单个 long 运行 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

不要在 table DDL 中使用 CLUSTERED BY,因为在插入期间使用 DISTRIBUTE BY、ORC w 索引和布隆过滤器 + SORT 可以以更灵活的方式实现相同目的。

分发+排序可以将ORC文件的大小极大地减少x3或x4倍。相似的数据可以更好的压缩,让内部索引更有效率。

另请阅读: 这是关于排序的相关答案:

您可以在 table DDL 中使用 CLUSTER BY 的唯一情况是当您加入两个大的 tables 时,它们可以被完全相同数量的桶进行桶装,以便能够使用 sort-merge-bucket-map-join,但实际上,您可以用相同的方式存储两个大 table 的情况非常罕见。只有 1 个桶没有意义,因为对于小的 table,您可以使用 map-join,只需在插入期间对数据进行排序以减少压缩数据大小。