Hive - 数据存储格式详解5(ORC格式)
作者:hangge | 2024-10-11 08:45
五、ORC 格式
1,基本介绍
(1)ORC(Optimized Row Columnar)格式是为 Hive 优化的一种高效存储格式。它在 RCFile 的基础上进行了改进,提供了更高的压缩比和更快的查询速度。
(2)ORC 的存储格式可以参考下面的官网图:
- 可以看出来 ORC 中的数据首先会被划分为多个 Stripe,每个 Stripe 250M。Stripe 表示 ORC 文件存储数据的地方。在 Stripe 内部包含了 Index Data,Row Data 和 Stripe Footer。
- Index Data 这里面存储的是索引数据。
- Row Data 里面存储的是具体的数据,这里面有多个行组,每 10000 行构成一个行组。
- Stripe Footer:里面存储的是数据所在的文件目录。
- 最下面的 File Footer:里面包含了 ORC 文件中 Stripe 的列表、每个 Stripe 的行数,以及每个列的数据类型。他还包含了每个列的最小值、最大值等信息。
- postscript:里面包含了压缩参数和压缩大小相关的信息。
(3)上面图看起来稍微有点复杂,简化一下就是下面这样的:
- 从这个图里面可以看出来 ORC 存储格式和 RCFile 存储格式在存储形式上没有特别大的区别,核心思想还是行列式存储。
(4)在创建 ORC 数据存储格式表的时候,所有关于 ORC 的参数都在建表语句中的 tblproperties 中指定,不需要在 hive 的命令行中使用 set 命令指定了。
注意:tblproperties 中可以指定多个参数,多个参数之间使用逗号分割即可。
create table t1( id int, name string ) stored as orc tblproperties("orc.compress"="NONE")
(5)ORC 支持的参数主要包括这些:
- orc.compress:表示 ORC 文件的压缩类型,支持 NONE、ZLIB 和 SNAPPY,默认值是 ZLIB。这里的 ZLIB 其实就和前面我们所说的 Deflate 压缩格式是类似的,因为 Deflate 压缩格式底层就是用的 ZLIB。
- orc.compress.size:表示每个压缩块的大小,默认是 256KB。这里面显示的是字节。
- orc.stripe.size:stripe 是 ORC 文件中存储数据的单位。这个配置表示在生成 stripe 的时候可以使用的内存缓冲池大小,默认值是 64M。这里面显示的是字节。
- orc.row.index.stride:行组级别索引的数据量大小,默认是 10000,必须要设置为大于等于 10000 的数值。表示每 10,000 行数据,建一次索引。
- orc.create.index:是否创建行组级别索引,默认是 true。
- orc.bloom.filter.columns:表示针对哪些列创建布隆过滤器,默认不创建。
- orc.bloom.filter.fpp:通过布隆过滤器可以通过较少的文件空间快速判断数据是否存在表中,但是也会存在将不属于这个表的数据判定为属于这个表的情况,这其实就是布隆过滤器的特性,这个特性可以称之为假正概率,我们可以调整这个概率。设置的概率越低,出现的误差就越小,但是布隆过滤器所需要的空间就越大。这个概率的取值范围在 0~1 之间,大于 0,小于 1。
(6)目前 ORC 只支持 NONE、ZLIB、SNAPPY、LZO 这三种压缩格式。默认是 ZLIB。
2,不使用压缩
(1)首先我们执行如下命令在 Hive 创建一个 ORC 存储格式的表,不使用压缩。注意:
- 这里需要在 stored as 后面指定 orc,并且在 tblproperties 中指定 "orc.compress"="NONE"。
- 针对 ORC 存储格式的表在控制压缩格式的时候是通过 orc.compress 指定的,不需要在 hive 中设置 hive.exec.compress.output 参数了。
create external table stu_orc_none_compress( id int, name string, city string ) row format delimited fields terminated by ',' lines terminated by '\n' stored as orc location '/stu_orc_none_compress' tblproperties("orc.compress"="NONE");
(2)创建后执行如下命令确认一下这个表,如果 INPUTFORMAT 使用的是 OrcInputFormat,说明这个表中需要存储 ORC 格式的数据。
show create table stu_orc_none_compress;
(3)然后从普通表中查询数据导入到这个 ORC 存储格式的表中。
- 在这里我们设置 mapreduce.job.reduces=1,表示将结果数据写入到一个数据文件中,这也便于后面验证这个数据文件是否支持 Split。
普通表 stu_textfile 中的数据来源可以参考我前面写的文章:Hive - 数据存储格式详解 2(TextFile 格式)
set mapreduce.job.reduces=1; insert into stu_orc_none_compress select id,name,city from stu_textfile group by id,name,city;
(4)查看结果数据可以发现,其体积为 1G,远小于原始的 TextFile 文件以及 SequenceFile 格式的 2G 大小,可以说明 ORC 在数据存储层面还是比较优秀的。
(5)接下来写一个 sql 查询表中的数据,验证是否支持切分:
select id,count(*) from stu_orc_none_compress group by id;
- 可以看到产生了 6 个 map 任务,说明 ORC 格式的文件是支持切分的。
(6)最后,这个表中的数据验证完毕之后,建议删除一下数据,释放 HDFS 空间。
hdfs dfs -rm -r -skipTrash /stu_orc_none_compress
3,使用 Zlib 压缩
(1)接下来我们构建一个新的压缩数据表,指定 ZLIB 压缩格式。
create external table stu_orc_zlib_compress( id int, name string, city string ) row format delimited fields terminated by ',' lines terminated by '\n' stored as orc location '/stu_orc_zlib_compress' tblproperties("orc.compress"="ZLIB");
(2)接下来通过 insert into select 从普通表中查询数据,插入到压缩表中。
- 在这里我们设置 mapreduce.job.reduces=1,表示将结果数据写入到一个数据文件中,这也便于后面验证这个数据文件是否支持 Split。
注意:为了能够控制任务最终产生的数据文件个数,在这里通过 mapreduce.job.reduces 来控制,并且 SQL 语句中需要有可以产生 shuffle 的操作,如果是普通的 select 语句,最终是不会产生 Reduce 任务的,那么 mapreduce.job.reduces 这个参数就无法生效了。
set mapreduce.job.reduces=1; insert into stu_orc_zlib_compress select id,name,city from stu_textfile group by id,name,city;
- 可以看到最终产生的数据文件大小为 243M:
(3)接下来写一个 sql 查询压缩表中的数据,确认一下是否验证是否支持切分:
select id,count(*) from stu_orc_zlib_compress group by id;
- 结果发现只产生了 1 个 Map 任务,这是因为 ORC 文件是分块存储的,每个分块包含多个行组。这些行组进一步划分为条带(Stripe)。通常一个 Map 任务会读取一个完整的压缩文件块,默认文件块大小为 256M,因此最终只会有 1 个 map 任务。
- 我们可以将表中数据删除,然后在 Hive 中将块大小设置为 128M 后重新导入数据:
hdfs dfs -rm -r -skipTrash /stu_orc_zlib_compress set hive.exec.orc.default.block.size=134217728; set mapreduce.job.reduces=1; insert into stu_orc_zlib_compress select id,name,city from stu_textfile group by id,name,city;
- 同时,Hive 在读取数据的时候目前使用的是 CombineHiveInputFormat,其在切分 Split 的时候会参考 mapred.max.split.size 参数的值。我们可以将 mapred.max.split.size 参数的值改为 128M:
set mapred.max.split.size=134217728;
- 再次查询可以发现产生了 2 个 Map 任务,说明 ORC 格式带压缩的文件也支持切分。
(6)最后,这个压缩表中的数据查看后最好删除一下,这样可以释放 HDFS 存储空间。
hdfs dfs -rm -r -skipTrash /stu_orc_zlib_compress
4,使用 Snappy 压缩
(1)接下来我们构建一个新的压缩数据表,指定 Snappy 压缩格式。
create external table stu_orc_snappy_compress( id int, name string, city string ) row format delimited fields terminated by ',' lines terminated by '\n' stored as orc location '/stu_orc_snappy_compress' tblproperties("orc.compress"="SNAPPY");
(2)接下来通过 insert into select 从普通表中查询数据,插入到压缩表中。
- 在这里我们设置 mapreduce.job.reduces=1,表示将结果数据写入到一个数据文件中,这也便于后面验证这个数据文件是否支持 Split。
注意:为了能够控制任务最终产生的数据文件个数,在这里通过 mapreduce.job.reduces 来控制,并且 SQL 语句中需要有可以产生 shuffle 的操作,如果是普通的 select 语句,最终是不会产生 Reduce 任务的,那么 mapreduce.job.reduces 这个参数就无法生效了。
set mapreduce.job.reduces=1; insert into stu_orc_snappy_compress select id,name,city from stu_textfile group by id,name,city;
- 此时发现结果数据文件有 500M。比 Zlib 的压缩性能差一些,因为 Zlib 的压缩比确实比 Snappy 高,Snappy 最主要的优点是压缩和解压速度快。
提示:在实际工作中,针对 ORC 格式而言,最常见的是使用 Snappy 压缩,主要看中他的压缩和解压速度快。
(3)接下来写一个 sql 查询压缩表中的数据,确认一下是否验证是否支持切分:
select id,count(*) from stu_orc_snappy_compress group by id;
- 结果发现只产生了 2 个 Map 任务,说明 ORC + Snappy 压缩的文件也支持切分。。
(4)最后,这个压缩表中的数据查看后最好删除一下,这样可以释放 HDFS 存储空间。
hdfs dfs -rm -r -skipTrash /stu_orc_snappy_compress
全部评论(0)