基本概念
行式存储和列式存储
先了解两种存储格式, 下图右边自上至下分别行式存储和列式存储对同一种逻辑表(图中左侧)的存储方式图示.
行存储
常见的关系型数据库都是行式存储的, 在我们查询的条件需要得到大多数列的时候, 相对列式格式, 查询效率更高. Hive默认的Text就是行式存储的.
列存储
列式存储, 它存储的方式是采用数据按照行分块,每个块按照列存储.
- 对于查询内容之外的列, 不必执行I/O和解压操作.
- 适合仅访问小部分列的查询. 如果查询的列很多, 则行存储格式更为适合.
- 列压缩的效率会更高, 尤其是列中取值不多的时候.
-
数据仓库中经常会有在非常大的数据集上对某些列进行聚合的需求, 列式格式非常符合这种场景的需要.
分片
MapReduce在读取数据的时候需要并行, 这就要求压缩后的文件可以分片读取. 分片对于MapReduce任务来说非常重要.
在考虑如何压缩那些将由MapReduce处理的数据时,考虑压缩格式是否支持分割是很重要的。考虑存储在HDFS中的未压缩的文件,其大小为1GB,HDFS的块大小为64MB,所以该文件将被存储为16块,将此文件用作输入的MapReduce作业会创建1个输人分片(split,也称为“分块”。对于block,我们统一称为“块”。)每个分片都被作为一个独立map任务的输入单独进行处理。
Hive中常用的存储格式
textfile
Hive的默认格式,存储方式为行存储。
- 空间利用率低
- 会有额外的序列化反序列化开销: 比如1234存储在文件中是字符串的形式, 转入程序中又是数字型的话读取和写入都会有额外的不必要的性能开销, 数量大的话性能影响就会更加显著.
- 如果压缩格式不支持分片, 则压缩后的结果也是无法支持分片的. 这会非常影响MapReduce任务执行效率.
- 判断分隔符需要珠子判断, 效率较低
ORCFile
ORCFile 可以理解为 Optimized RCFile, 就是RCFile的优化版. 尤其是弥补了查询和存储效率方面的缺陷. 它同样不喜欢小文件. 特性如下:
- 支持所有的hive类型, 包括复合类型: structs, lists, maps 和 unions.
- 支持分片
- 可以仅返回查询的列, 减少io消耗, 提升性能.
- 可以与Zlib, LZO和Snappy结合进一步压缩.
- 不支持其他的查询引擎, 比如impala.
- 内件索引: 其存储了文件级别, stripe级别, row级别的索引, 其中统计了minimum and maximum values and for numeric types the sum. 在Hive 1.2 (我们现在满足)索引中还包含了
bloom filters
(提供更多的查询过滤)
缺点: - 对模式演化(schema evaluation)支持较差, 如果
SequenceFile
二进制文件, 行存储, 以key-value的形式序列化到文件中. 可分片, 即使与不支持分片的压缩算法结合. 压缩存储方式分为: 无压缩, 记录级压缩, 块压缩. 无论哪种存储方式, 每个SequenceFIle都包含一个通用的头部格式. 无压缩的SequenceFile占用I/O资源很高, 对比其他格式没有什么优, 不推荐这种存储方式, 使用SequenceFile时都要指定压缩, 大多数情景下, 块级压缩最为高效.
Parquet
Parquet和ORC有很多相似之处, 但是Parquet更有意成为hadoop上通用的存储格式. 它可以与impala, Spark, Pig等引擎结合使用. 它可以指定每一列的压缩方式, 从而实现更高效的压缩. Parquet旨在设计为支持复杂嵌套数据的存储, 比如json,
压缩
Snappy
Google开发的一种压缩编解码器, 用于实现高速压缩, 适当兼顾压缩率, 平衡了压缩速率和文件大小. 但是有一点, Snappy是不支持分片的, 所以它需要和容器格式相互联合使用(如SequenceFile和Avro).
LZO
压缩率和速度与Snappy相近, 由于许可协议的原因, LZO不能打包进hadoop中进行分发, 需要单独安装. Snappy可以与Hadoop打包分发. 它可以支持分割, 但是要求建立索引.
Gzip
压缩速率非常好, 平均可以达到Snappy的2.5倍. 但是相应的, 写入相对较Snappy慢了一倍. Gzip同样也是不支持分片的, 所以应该与容器格式联合使用. Gzip更适合将数据进行归档.
bzip2
压缩性能比Gzip还要高9%, 但是要消耗更多的读取, 写入性能. 一般来说bzip2要比Gzip慢十倍. 所以bzip2应该不是hadoop集群上理想的编解码格式, 除非需求以为了减少空间占用为主. 比如将数据进行归档, 但是使用的时候也要考虑资源的消耗. 另外的, bzip2是支持数据分割的.
几种压缩算法的简单对比
压缩方式 | 压缩效率 | 压缩速度 | 是否可分割 |
---|---|---|---|
Gzip | 中高 | 中 | 否 |
bzip2 | 高 | 慢 | 是 |
Snappy | 低 | 快 | 否 |
LZO | 低 | 快 | 是(但是要求建立索引) |
Zlib | 低 | 快 | 是 |
建议
数据仓库往往都是一次写入, 多次读取, 尤其是经常取少部分列以及可能会对他进行聚合操作的情况, 比较适合使用列式存储, 这里我推荐使用orc, 默认结合Zlib进行压缩.
如果是经常查询多数列就应该使用行存储格式. 比如Avro, 推荐配合snappy压缩算法使用, 均衡空间和时间.
建议使用列式存储的情况
- 行数很多且列中的值有很多重复,比如年龄最多也不会超过150种,这样的话列式存储可以更高效率的使用存储。
- 表有很多列,实际使用中往往只是查询少量的列,这样列式存储的IO效率会相对更高。
- 聚合查询。
Text格式不推荐使用, 尤其与不支持分片的压缩联合使用的时候.
参考
Apache ORC