重点:ORC只支持snappy压缩格式,但是snappy不支持分片,如果文件较大只能通过一个task读取,会导致map读取的数据倾斜;Parquet支持snappy和lzo压缩,lzo支持分片,所以如果存在大文件(压缩之后的大小远大于128M),则适合采用 Parquet + lzo压缩的方式。
ORC和Parquet都属于行列式的存储格式,那么在Hive中如何进行选择呢?
ORC
表配置属性,除了上面的 orc.compress 压缩格式,还有:
orc.compress:表示ORC文件的压缩类型,「可选的类型有NONE、ZLB和SNAPPY,默认值是ZLIB(Snappy不支持切片)」—这个配置是最关键的。
orc.compress.size:表示压缩块( chunk)的大小,默认值是262144(256KB)。
orc.stripe.size:写 stripe,可以使用的内存缓冲池大小,默认值是67108864(64MB)
orc. row. index.stride:行组级别索引的数据量大小,默认是10000,必须要设置成大于等于10000的数
orc. create.index:是否创建行组级别索引,默认是true orc. bloom filter. columns:需要创建布隆过滤的组。
orc.bloom.filter.fpp:使用布隆过滤器的假正( False Positive)概率,默认值是0. 扩展:在Hive中使用
bloom过滤器,可以用较少的文件空间快速判定数据是否存表中,但是也存在将不属于这个表的数据判定为属于这个这表的情况,这个称之为假正概率,开发者可以调整该概率,但概率越低,布隆过滤器所需要
Parquet
既然ORC都那么高效了,那为什么还要再来一个Parquet,那是因为「Parquet是为了使Hadoop生态系统中的任何项目都可以使用压缩的,高效的列式数据表示形式」
表属性配置:
parquet. block size:默认值为134217728byte,即128MB,表示 Row Group在内存中的块大小。该值设置得大,可以提升 Parquet文件的读取效率,但是相应在写的时候需要耗费更多的内存
parquet.page:size:默认值为1048576byt,即1MB,表示每个页(page)的大小。这个特指压缩后的页大小,在读取时会先将页的数据进行解压。页是Parquet操作数据的最小单位,每次读取时必须读完一整页的数据才能访问数据。这个值如果设置得过小,会导致压缩时出现性能问题
parquet.compression:默认值为 UNCOMPRESSED,表示页的压缩方式。「可以使用的压缩方式有UNCOMPRESSED、 SNAPPY、GZP和LZO」。
Parquet enable. dictionary:默认为tue,表示是否启用字典编码。
parquet. dictionary.page.size:默认值为1048576byte,即1MB。在使用字典编码时,会在Parquet的每行每列中创建一个字典页。使用字典编码,如果存储的数据页中重复的数据较多,能够起到一个很好的压缩效果,也能减少每个页在内存的占用。
存储和压缩格式的搭配:
根据ORC和parquet的要求,一般就有了
1、ORC格式存储,Snappy压缩
2、Parquet格式存储,Lzo压缩
3、Parquet格式存储,Snappy压缩
因为Hive 的SQL会转化为MR任务,如果该文件是用ORC存储,Snappy压缩的,因为Snappy不支持文件分割操作,所以压缩文件「只会被一个任务所读取」,如果该压缩文件很大,那么处理该文件的Map需要花费的时间会远多于读取普通文件的Map时间,这就是常说的「Map读取文件的数据倾斜」。
那么为了避免这种情况的发生,就需要在数据压缩的时候采用bzip2和lzo等支持文件分割的压缩算法。但恰恰ORC不支持刚说到的这些压缩方式,所以这也就成为了大家在可能遇到大文件的情况下不选择ORC的原因:避免数据倾斜。
「所以在实际生产中,使用Parquet存储,lzo压缩的方式更为常见,这种情况下可以避免由于读取不可分割大文件引发的数据倾斜。 但是,如果数据量并不大(预测不会有超大文件,若干G以上)的情况下,使用ORC存储,snappy压缩的效率还是非常高的。」