pgrust 大对象与 TOAST:超大字段存储的完整方案 pgrust 大对象与 TOAST超大字段存储的完整方案【免费下载链接】pgrustPostgres rewritten in Rust, now faster than Postgres and Clickhouse项目地址: https://gitcode.com/GitHub_Trending/pg/pgrust当数据库里出现几 MB 甚至几 GB 的图片、文档或 JSON 时如何高效存储而不拖垮查询性能pgrust 大对象与 TOAST 机制给出了完整答案。pgrust 是一个用 Rust 重写 PostgreSQL 的开源数据库目标是与 Postgres 18.3 保持磁盘级兼容并在此之上实现更快的性能——在最新的未发布版本中事务负载比 Postgres 快 50%分析负载快约 300 倍。本文将带新手彻底搞懂 pgrust 的超大字段存储方案行内字段如何自动压缩外置TOAST海量二进制数据如何通过大对象Large Object分页存储以及两者的选用场景。为什么要单独设计超大字段存储PostgreSQL 的数据页默认只有 8KB一条记录不能跨页存放。这带来一个经典难题场景字段大小直接存入行内的问题用户头像、PDF 文件几 MB一行塞不下频繁 IO大型 JSON/日志文本几百 KB每次查询都要搬运大块数据视频切片、备份数据几百 MB远超单行上限Postgres 的解决方案是两条腿走路TOAST 负责行内大字段的自动处理大对象负责任意大小的二进制流。pgrust 完整移植了这两套机制并保留相同的磁盘格式因此可以直接挂载已有的 Postgres 18.3 数据目录。TOAST行内大字段的自动压缩与外置TOASTThe Oversized-Attribute Storage Technique是 PostgreSQL 处理大字段的核心技术pgrust 将其完整用 Rust 重写。当一行数据超过约 2KB 阈值时TOAST 会自动介入整个过程对上层 SQL 完全透明。TOAST 的三种策略TOAST 对每个字段提供四种存储策略可在建表时用STORAGE关键字指定PLAIN禁止压缩与外置仅限定长类型EXTENDED默认先尝试压缩压缩效果不佳再外置EXTERNAL直接外置不压缩MAIN优先压缩尽量留在行内。当行大小超过TOAST_TUPLE_THRESHOLD在 pgrust 中为 2032 字节时系统自动挑选大字段进行压缩或拆分。压缩与外置的实现路径pgrust 中 TOAST 的核心逻辑分布在几个专注的 crate 中crates/backend/access/heap/heaptoast/src/lib.rs定义TOAST_TUPLE_THRESHOLD、TOAST_MAX_CHUNK_SIZE等关键常量与入口函数heap_toast_insert_or_updatecrates/backend/access/common/toast_internals/src/lib.rs实现toast_save_datum把大值切块写入 TOAST 表、toast_fetch_datum按块重组回完整值、toast_delete_datum回收外置块以及toast_compress_datum压缩crates/backend/access/common/toast_compression/src/lib.rs在 PGLZ 与 LZ4 两种压缩算法间做选择PGLZ 始终可用crates/backend/access/table/toast_helper/src/lib.rs表访问层对 TOAST 的辅助封装crates/backend/catalog/toasting/src/lib.rs负责建表时自动创建配套的pg_toast表。TOAST 的存储细节外置后的值被切成固定大小的块每个块是一行独立记录存在专属的pg_toast_xxx表中单块最大载荷TOAST_MAX_CHUNK_SIZE由外部指针上限推导而来块记录包含外置值的 OID、块序号和数据本身读取时按块序号顺序扫描重组写入时按需追加新块。对于大对象这种特殊 varlena 类型还有一层间接指针indirect pointer优化若外置指针本身也太大则再包一层间接指针避免指针膨胀。这层逻辑同样保留在toast_internals的 detoast 静态处理中。大对象任意大小二进制流的正统方案TOAST 适合行内嵌大值而**大对象Large Object**面向的是真正的大文件——它把数据分成 2048 字节LOBLKSIZE即 8KB 数据页的 1/4的页存储在系统表pg_largeobject中最大可达约 4TB。大对象的实现路径pgrust 将 Postgres 的inv_api.c完整移植到 Rust位于crates/backend/storage/large/object/src/lib.rs服务端大对象字节级 API包含inv_create创建、inv_open打开并做权限检查、inv_read顺序读、inv_write读写改页、inv_truncate截断、inv_seek/inv_tell随机定位、inv_drop删除crates/backend/catalog/pg_largeobject/src/lib.rspg_largeobject系统表的目录层支持crates/backend/catalog/pg_largeobject_seams/src/lib.rs目录访问的 seam 接缝层crates/backend/libpq/be_fsstubs/src/lib.rs把底层 API 包装成 SQL 可直接调用的lo_*函数。值得留意的是原 C 代码用文件级静态变量缓存pg_largeobject的关系引用pgrust 的 Rust 版改为在每次操作的内存上下文中直接打开关系、结束时以NoLock释放语义等价且更符合 Rust 的所有权模型——这正体现了用 Rust 重写并保持行为一致的项目哲学。大对象的使用方式SQL 层通过lo_*函数操作大对象-- 创建大对象 SELECT lo_create(0); -- 从文件导入 SELECT lo_import(/path/to/bigfile.bin); -- 导出到文件 SELECT lo_export(oid, /path/to/out.bin); -- 在事务中读写客户端 API 通过 lo_open/lo_read/lo_write大对象要求在事务块内操作且支持随机读写与截断非常适合存储大文件、图片素材和流式数据。关键数值一览参数值说明LOBLKSIZE2048 字节大对象分页大小等于 BLCKSZ/4MAX_LARGE_OBJECT_SIZEINT_MAX × 2048大对象理论上限约 4TB写入策略读改写 补洞覆盖写入时先读整页再修改跳跃写入自动填充空洞TOAST 与大对象如何选择两者都能存放大字段但定位截然不同TOAST藏在行内的自动挡。字段本身仍是普通列参与查询、索引、WHERE 条件只是物理上被拆到旁路表。适合 JSON、长文本、中等体积的二进制几百 KB 到几 MB。大对象独立于行的文件系统。一个 OID 指向一串可随机读写的字节流但不能直接作为列被 WHERE 引用或建索引。适合超大文件、流式内容、需要随机访问的场景。一句话总结要查询语义选 TOAST要超大文件选大对象。如何上手体验 pgrustpgrust 目前处于快速发展期已通过超过 46000 条回归查询、与 Postgres 18.3 磁盘兼容。想体验它的超大字段存储能力可以克隆仓库自行构建git clone https://gitcode.com/GitHub_Trending/pg/pgrust项目采用 workspace 组织所有存储引擎模块都可在crates/backend/下按名称检索例如想看 TOAST 压缩细节就找toast_compression想看大对象分页逻辑就找storage/large/object——代码注释保留了与 C 源文件的对照关系是学习存储引擎的绝佳教材。结语从自动压缩外置的 TOAST到可随机读写的 2KB 分页大对象pgrust 用 Rust 完整复刻了 PostgreSQL 的超大字段存储方案并在内存管理、错误处理、所有权模型上做了更安全的现代化改造。对于想要深入理解数据库存储原理或正在评估 Rust 重写 Postgres 可行性的读者这套TOAST 大对象的组合就是最好的起点。【免费下载链接】pgrustPostgres rewritten in Rust, now faster than Postgres and Clickhouse项目地址: https://gitcode.com/GitHub_Trending/pg/pgrust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考