特点:适合OLTP,写密集的场景(或是要求所有列的查询);
特点:适合OLAP,读密集的场景,可以列裁剪,压缩率高;
文件组织格式:首尾都有magic number校验这个是parquet文件;Footer放在文件末尾,存放了元数据信息,包括schema信息,以及以及每个row group的meta data和统计信息;row group(默认128M)是一批行数据的组成(例如0~1万行数据),row group中的每个column是一个列;一个列又分为多个page(默认1M)页,页是最小的编码单位;二进制存储;
谓词下推:parquet原生支持谓词下推;parquet每次扫描一个row group的数据,每个row group都是按列存储的,便可以只读取需要的column chunk列块,每个column chunk会生成统计信息(最大值、最小值、空值个数),通过这些统计信息和该列的过滤条件,可以判断该row group是否需要扫描;
应用:存储parquet文件时,通常会按照HDFS的Block大小设置row group的大小,因为MR和Spark在读取文件时一个task读取的最小单元就是一个Block,这样可以增大任务的并行度;相对于ORC格式,parquet对嵌套类型的支持更好,内部默认使用snappy压缩;但是压缩率、查询性能比ORC差一点点(有的测试比ORC要好),并且不支持update和acid,但是olap场景也不需要update和acid;常用于impala和spark;spark中row group大小为 parquet.block.size(默认128M,压缩后的),row group是一个切片的最小单位;page大小为parquet.page.size(默认1M,压缩后的),page是压缩和一次读取的最小单位;
spark和hive读取parquet:spark会使用自定义的serde来读取parquet文件(性能更高),如果读取异常,可以改用hive的serde来读取,将参数spark.sql.hive.convertMetastoreParquet(默认true)设为false即可;spark在处理时会缓存parquet的元数据信息,如果其他地方修改了,需要手动刷新;
结合压缩: parquet + snappy(lzo)的方式用的较多;这里要特别注意snappy压缩,如果用snappy对一个text文件压缩,那么这个文件是不可分割的,而使用snappy对parquet内部的page压缩,则内部压缩后的文件是可分割的,并且读取时是以row group为切片的;orc同理;parquet+snappy综合性能最高;spark中parquet的压缩格式是spark.sql.parquet.compression.codec(默认是snappy);
压缩格式:spark.io.compression.codec(默认lz4,spark2.2之前是snappy)
序列化的地方:广播变量、shuffle数据、缓存rdd(缓存级别带序列化SER)等;
Kryo序列化:Kryo序列化性能(大小和时间)是spark默认的java序列化的10倍(实际中可能3~6倍);但是Kryo需要注册自定义的类才能达到高性能,这也是spark默认没有选择Kryo的唯一原因;因为如果不注册自定义的类,Kryo需要为每一个对象保存它的全类名,这是非常浪费的;所以序列化大量没有注册的自定义对象时,序列化后的大小甚至会大于java序列化后的大小还大,但是序列化的时间还是优于java序列化的;
使用步骤:设置spark的序列化器,注册自定义类型;
val conf = new SparkConf()
// 设置序列化器为KryoSerializer。
conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
// 注册要序列化的自定义类型。
conf.registerKryoClasses(Array(classOf[MyClass1], classOf[MyClass2]))
原文:https://www.cnblogs.com/shendeng23/p/15240802.html