【AICon】AI 基础设施、LLM运维、大模型训练与推理,一场会议,全方位涵盖! >>> 了解详情
写点什么

数据库内核杂谈(三十一)- 大数据时代的存储格式 -Parquet(2)

  • 2023-05-04
    北京
  • 本文字数:3012 字

    阅读完需:约 10 分钟

数据库内核杂谈(三十一)- 大数据时代的存储格式-Parquet(2)

欢迎阅读新一期的数据库内核杂谈。上一期杂谈介绍了 Parquet 存储格式。这一期,咱们收个尾,介绍一下 Parquet 如何支持表结构的演进(schema evolution)以及使用 Parquet 时的一些最佳实践。

支持 schema evolution(add/delete/rename columns)


在大数据业务驱动下,数据的表结构(table schema)会因为需求快速迭代而被改变。大数据系统需要具备在不影响现有应用程序或工作流的情况下,支持表结构演进(schema evolution)的能力。Parquet 格式为 schema evolution 提供了良好的功能支持,使其成为现代大数据系统的理想存储格式。

 

首先,Parquet 的 datafile 存储了数据的 schema information;这个信息以元数据的形式存储在数据文件中,见下图(源于上一期的实操数据)。但是,这个 schema 信息,并不是作为查询引擎的 source of truth,只是定义了这个数据文件存储的 schema(相当于这个 datafile 的 source of truth)。这个信息用来对于数据读取做优化以及确保查询引擎可以正确地解析数据。


(Parquet datafile 中存储了 schema 信息)


表格式的 source of truth 通常存储在大数据系统的元数据中心(比如 Hive Metastore,或者是 Apache Spark Catalog)。元数据中心会记录 schema 的改变,比如新增或者删除 column。同时也会保存 schema 的所有历史 version。

 

我们通过一个例子(接着使用 student 表),来看 Parquet 的 schema 信息,结合数据系统的 metadata service 是如何支持 schema evolution 的。表 student 的初始 schema 定义如下:


Table student(bigint id, string name, int age, string country, string home_address)
复制代码

 

在某个时间点,schema 改成了如下:


Table student(bigint id, string name, int age, string country, string school_name optional)
复制代码

(添加了一个新的 optional 的 field school_name,同时,为了保护隐私,删除了 home_address)。系统在改变 schema 后,新导入(插入)的数据,都用了最新的 schema。即,新的 Parquet datafile 只有 id, name, age, country 和 school_name 这些 columns,但旧的 datafile 有 id,name,age,country 和 home_address 这些 columns。

 

此时,用户对数据进行查询时,查询引擎会根据数据系统的 metastore 中存储的 schema 信息,结合读取的 Parquet datafile 上的 schema 信息,来决定如何正确地读取数据:1)当读取最新 Parquet datafile 的时候,因为 schema 是匹配的,没有任何问题。2)但读取旧 Parquet datafile 的时候,查询引擎会发现 home_address 这个 column 在新的 schema 已经被删除了。因此,没有必要读取这个 column 的数据(归功于 Parquet 的列存设计,可以避免这一块数据的 IO);同时,查询引擎发现旧 datafile 并不存在 school_name 这个 column,查询引擎可以直接返回 NULL 值或者是 default 值。3)同理可得,当我们使用一个旧的 schema 去读取数据的时候(这种情况比较少,比如 time-travel query),对于新 schema 的 column mismatch 也可以通过相同的方法来返回数据(对于已经删除的 column,返回 NULL 值或者 default 值;对于新增的 column,不用读取这部分数据)。

 

虽然 Parquet 本身不支持 rename column 操作(因为 Parquet 的 datafile 只存储了当前数据 schema 信息),但是配合 metadata service 的 schema versioning,依然可以通过新旧 column 的 mapping 信息来支持 rename column 后的数据读取。对于 column 的 type change,查询引擎配合新旧 type 的 compatibility,就可以支持数据的读取,比如 int -> bigint 等(可能会因为数据转换导致精度缺失)。

最佳实践


Devils in the detail,Parquet 有很多可配置的使用选项。合理、正确的配置才能做到在查询性能、存储优化上获得收益和平衡。在本节中,我们讨论使用 Parquet 的一些需要关注的点和相应的最佳实践。

 

压缩算法(compression)和编码选项(encoding)


Parquet 支持多种压缩和编码算法,来优化存储和查询性能。选择合适的组合对于实现最佳效果至关重要。下面是一些最佳实践:

 

压缩:Parquet 支持几乎所有流行的压缩算法,包括 Snappy、Gzip 和 LZO。Snappy 在压缩比和速度之间提供了良好的平衡,使其成为常见的选择。Gzip 提供更好的压缩比,但以较慢的压缩和解压速度作为代价。LZO 优化了速度,但提供了较低的压缩比。高度压缩的数据可能需要更多的 CPU 资源来进行解压缩,影响查询性能。所以,根据具体的业务需求(是追求查询性能还是追求存储成本)选择一个平衡的压缩算法和压缩级别。

 

编码:Parquet 支持多种编码方案,如 dict encoding, run-length encoding(RLE)和位打包(bit packing)。编码的选择取决于数据特征。例如,对于基数较低(不同值较少)的列,字典编码效果很好,而对于单调递增或递减值的列,增量编码更为合适。在绝大部分情况下,让 Parquet 自行选择就好,Parquet 会根据 column 的数据类型和分布自动选择最高效的编码技术。

数据文件大小和分区


优化文件大小和合理的分区策略可以显著地提高查询性能。

 

文件大小:将文件大小控制在 64MB 到 1GB 之间。较大的文件可以实现更好的压缩,减少管理众多小文件的开销,提高查询性能。然而,非常大的文件可能会导致内存使用增加和处理速度变慢。最佳实践就是,根据实际的查询逻辑,尝试配置不同文件大小,以找到平衡点。

 

分区:分区策略并不只适用于 Parquet。根据经常用作查询过滤器的列对数据进行分区。这允许查询引擎仅读取相关的分区,减少 I/O 开销并提高查询性能。常见的分区策略包括按日期或分类变量进行分区。避免创建太多小分区,因为这可能导致管理元数据的开销增加。


避免创建过多小文件,因为这可能对查询性能产生负面影响。

Schema evolution 支持


在第一节中,我们介绍了 Parquet 如何支持 schema evolution。下面是一些相关的最佳实践:

 

添加新 column:在添加新 column 时,尽量将其设为可选,并提供默认值。这确保了向后兼容性,因为查询引擎可以为旧数据中的新 column 返回空值或默认值。

 

重命名 column:由于 Parquet 不直接支持 column 重命名,所以需要和支持重命名的数据系统引擎联动。最佳实践就是规范命名,尽可能避免重命名。

 

更改列数据类型:将数据类型更改限制为扩展数字类型或将可为空类型更改为不可为空类型。对于更复杂的更改,使用查询引擎在查询进行时(runtime)执行类型转换。

分析型查询优化工作


过滤和排序:利用 Parquet 的谓词下推(predicate push down)和列剪裁(column prune)功能来优化查询性能。将过滤器下推到存储层可减少从磁盘读取的数据量,而列剪裁可确保只读取相关列。

 

向量化查询处理:使用支持向量化查询的查询引擎(如 Apache Arrow),以进一步提高列式数据的查询性能。

总结


这一期,咱们对 Parquet 存储格式的内容进行了收尾,聊了一下 Parquet 是如何配合大数据系统做 schema evolution 的,以及一些实际使用中的最佳实践。

写在 5 周年之际


数据库内核杂谈,最开始是在简书开始连载的(附上了第一篇的截图)。也算是一个阴差阳错的契机吧(说起来都物是人非啦。哈哈哈!)不知不觉,已经快 5 周年了!感谢大家的陪伴和支持!也感谢一下自己的坚持。周期性的更新杂谈也是反向 push 我不断去学习。期待下一个 5 年。

 

 

内核杂谈微信群和知识星球


内核杂谈有个微信群,大家会在上面讨论数据库相关话题。目前群人数快 400 人啦,所以已经不能分享群名片加入了,可以添加我的微信(zhongxiangu)或者是内核杂谈编辑的微信(wyp_34358),备注:内核杂谈。

 

除了数据库内核的专题 blog,我还会 push 自己分享每天看到的有趣的 IT 新闻,放在我的知识星球里(免费的,为爱发电),欢迎加入。



2023-05-04 23:114063

评论 1 条评论

发布
用户头像
"在绝大部分情况下,让 Parquet 自行选择就好,Parquet 会根据 column 的数据类型和分布自动选择最高效的编码技术。"官方在哪里有介绍到呢?rust的parquet的库没有这种特性吧https://github.com/jorgecarleitao/parquet2
2023-05-07 00:17 · 北京
回复
没有更多了
发现更多内容

双11大促 | 消息推送资源包6折购!一键集成华为、小米等多厂商推送通道

蚂蚁集团移动开发平台 mPaaS

消息推送 push mPaaS 双11 促销

crm软件有哪些比较好?国内目前好用的crm系统推荐!

低代码小观

CRM 管理系统 企业管理系统 CRM系统 客户关系管理系统

移动App应用进入存量竞争阶段,如何全维度洞察用户体验?

博睿数据

AI 算法在视频可分级编码中的应用

融云 RongCloud

人工智能 音视频 编解码

如何 30 分钟搭建一个语聊房

融云 RongCloud

浅谈微信朋友圈架构设计

张平

架构实战营

万字长文聊哈希

程序厨

面试 哈希 哈希表

字节Android Native Crash治理之Memory Corruption工具原理与实践

字节跳动终端技术

字节跳动 Android; 火山引擎

可观测性架构实践

郑印

[架构实战营] 模块二作业

张祥

架构实战营

工具:Juypter Notebook

正向成长

Jupyter Notebook

彻底理解 AQS我是懂了,你呢?

何小事儿

Java 多线程 并发

语聊房高质量音乐伴奏的实现

融云 RongCloud

语聊房 音乐播放

BoCloud博云完成 E 轮融资

BoCloud博云

云计算 云原生 博云

Hudi 在字节实践记录

Clarke

活动日程首公布|Apache ShardingSphere Dev Meetup 亮点新揭秘

SphereEx

ShardingJDBC ShardingSphere 技术沙龙 SphereEx

“极速、统一、开放”,StarRocks开启企业数据分析新局面

crm的核心是什么?CRM对企业的核心作用是什么?

低代码小观

企业 企业管理 CRM 管理系统 CRM系统

DDD战术设计实践

郑印

DDD

JavaScript 解构赋值 5 个常见场景和实例

devpoint

JavaScript 大前端 ES6 11月日更

FabEdge 和 SuperEdge 联合在边缘 K8s 集群支持原生 Service 云边互访和 PodIP 直通

BoCloud博云

云原生 边缘计算 superedge FabEdge

40多场面试,凝聚成了这篇文章!

程序厨

面试 面试技巧 秋招

10月书讯 | 跟着泰拉去冒险

图灵教育

编程 程序员 书单

优先队列一些记录以及解题思路

数据结构 Go 语言 优先队列

GaussDB (for Cassandra) 数据库治理:大key与热key问题的检测与解决

华为云开发者联盟

数据库 分布式数据库 key GaussDB (for Cassandra) 数据库治理

hadoop nameNode/datanode 稳定性&性能改进点

Clarke

机器人存在的问题挑战

【架构设计总结】

Ryoma

糟糕程序员的20个坏习惯

Kaito

架构 程序人生 后端 编程修养

揭秘 MatrixDB 数据库内核技术,可编程的数据库!

YMatrix 超融合数据库

数据库 时序数据库 分布式时序数据库 MatrixDB 超融合时序数据库

看完电影《门锁》感觉脊背发凉,智慧园区给你安全感!

ThingJS数字孪生引擎

可视化

数据库内核杂谈(三十一)- 大数据时代的存储格式-Parquet(2)_大数据_顾仲贤_InfoQ精选文章