万物皆可KV(4)Neon PageServer 存储布局分析
2026/7/29 18:54:46 网站建设 项目流程

1. 结论

Pageserver 的 Key 不是 SQL 主键;它用tablespace/database/relation/fork/block等物理地址形成 18 字节 Key,用 LSN 形成版本维度,Value 保存完整页 Image 或可重放 WAL delta。表名、列、SQL 类型、约束和 PostgreSQL 索引结构都仍在 PostgreSQL 页内,不形成独立 Pageserver KV。

2. 总体 Key/Value 布局

租户 / shard / timeline ← 位于目录、对象名和 layer summary,不进入 18B Key └─ Pageserver 版本化 Key/Value ├─ Schema / 物理元数据 │ ├─ 00 DB directory / relmap / relation directory / relation size │ ├─ 01 SLRU directory / segment size │ ├─ 02 pg_twophase directory │ ├─ 03 control / checkpoint / 旧 AUX v1 │ └─ 60..7E 稀疏元数据 │ ├─ 62 AUX v2 hash Key -> 路径/文件 Value │ ├─ 63 replication origin origin Key -> LSN Value │ └─ 65 relation existence v2 relation Key -> "r"/empty └─ Data ├─ 00 relation fork block Key -> 8KiB Image 或 WAL delta ├─ 01 pg_xact / pg_multixact block Key -> 8KiB Image 或专用 delta └─ 02 pg_twophase file Key -> 原始文件 Image 写入: (18B Key, 8B LSN, Value) -> Value::ser 追加到 ephemeral file -> 内存 BTreeMap<CompactKey, LSN -> offset> -> freeze -> delta layer: B-tree<(18B Key | 8B LSN), BlobRef> + serialized Value blob 读取: get(Key, requested LSN) -> 从新到旧遍历 delta/image layers -> 收集 WAL delta,直到 Image 或 will_init delta -> 按 LSN 正序 redo -> 返回该 Key 在 requested LSN 的完整 Bytes 压实: 多个历史 Value -> reconstruct -> image layer image layer: B-tree<18B Key, blob offset>,LSN 位于 layer header,Value 是原始完整 Image

2.1 公共逻辑 Key

所有实际 layer 索引中的逻辑 Key 都是 18 字节:

Key = field1:u8 | field2:u32 BE | field3:u32 BE | field4:u32 BE | field5:u8 | field6:u32 BE
Key 规则源码事实
总宽度固定 18B,无分隔符、长度前缀或转义。
排序字段顺序与 18B 大端字节序一致;无符号数值按字节比较即可保持升序。
版本逻辑 Key 本身不含版本。Delta layer 的物理索引 Key 追加LSN:u64 BE,成为 26B;Image layer 把单一 LSN 放在 layer header。
metadata Key稀疏 metadata 编码器先构造 16B:首字节 + 15B payload;转为通用 Key 时,field2高 16 位补零,最终 layer 索引仍写 18B。
CompactKey内存使用 128 位整数;field2只保留低 16 位。因此正常生产 relation 依赖内置 tablespace OID 可表示,用户自定义 tablespace 不受支持。
空间边界0x00..0x03为 dense 对象;0x60..0x7E被当作 sparse metadata,可容忍 Key 缺失。
NULL/collation/降序不适用。Key 字段都是物理标识;SQL NULL、collation 和索引升降序留在 PostgreSQL 页内部。

2.2 layer 中真实的 Key/Value 关系

B-tree KeyB-tree Valueblob ValueLSN
Delta layerKey(18B) | LSN(BE u64),共 26B5B 大端BlobRef;逻辑值为blob_offset << 1 | will_init完整Value::ser;1B/4B blob 长度头;不压缩在 B-tree Key 中
Image layerKey(18B)5B 大端 blob offset重建后的原始 Image Bytes,不带Value::Image枚举标签;1B/4B blob 长度头;可 Zstd在 layer summary 中

B-tree 使用 8KiB 页。节点头是child_count:u16 BE | level:u8 | prefix_len:u8 | suffix_len:u8,后接公共 Key 前缀、定长 Key 后缀数组和每项 5B Value。写入必须严格递增;页满时可提取页内公共前缀。

blob 长度头:

payload_len < 128: 0LLLLLLL payload_len >= 128: 1CCCllll llllllll llllllll llllllll CCC=000:未压缩 CCC=001:Zstd 最大 payload 长度:0x0FFF_FFFF

当前 layer blob 和 B-tree 节点没有独立 checksum 字段;完整性主要由文件、summary 一致性检查及远端对象层承担。

2.3 逻辑 Value envelope

Delta layer 使用大端、定宽整数的 bincode/Serde 编码:

Value::Image(bytes) = variant:u32 BE = 0 | len:u64 BE | bytes Value::WalRecord(record) = variant:u32 BE = 1 | NeonWalRecord variant:u32 BE | variant fields

Value 没有独立格式版本字段。枚举顺序和字段序列属于永久格式兼容面;layer 外层另有 storage format version。Image layer 不再保存上述 envelope,只保存重建后的 Image payload。

3. 真实 Key/Value 示例

以下 5 组字节由临时 codec probe 直接调用当前生产 Key 构造器、AUX 编码器,并直接编译当前Value/NeonWalRecord定义后生成,统一选择LSN=0/100,即数值0x100Delta index Key是真实持久 delta B-tree 的完整 26B Key;Delta Value是 blob 长度头之后的完整 Value payload。

3.1 初始化空 DB directory

  • 逻辑输入:新 timeline,尚无数据库目录项,LSN0/100
  • 写入形式put(DBDIR_KEY, Value::Image(BeSer(DbDirectory{dbdirs:{}})))

Key(定位整个 PGDATA 的数据库目录)

可读分段:00/00000000/00000000/00000000/00/00000000 逻辑 Key 转义/Display: 000000000000000000000000000000000000 逻辑 Key Hex: 000000000000000000000000000000000000 Delta index Key Hex(逻辑 Key | LSN): 0000000000000000000000000000000000000000000000000100

Value(保存空目录集合)

内层 Image 解码:HashMap<(spcnode, dbnode), relmap_exists>,元素数 0 内层 Image Hex:0000000000000000 Delta Value 长度:20B Delta Value Hex: 0000000000000000000000080000000000000000 分段: 00000000 -> Value::Image tag 0000000000000008 -> Image 长度 8 0000000000000000 -> HashMap 元素数 0 delta blob 完整前缀:14(payload 长度 20)| 上述 20B

编码与使用

Key: 固定 DBDIR 地址 -> 18B BE Key -> 追加 LSN 得 26B delta Key Value:空 HashMap -> BE bincode 8B -> Value::Image envelope 写入: commit -> put_batch -> ephemeral file -> delta layer 读取: get(DBDIR_KEY, LSN) -> Value::des -> Image -> DbDirectory::des 回表: 不需要;这是 Pageserver 自己的物理目录元数据

3.2 relation 16384 main fork 的大小为 42 页

  • 逻辑输入:默认 tablespace1663、database OID5、relnode16384、main fork0,大小42页,LSN0/100
  • 写入形式put(rel_size_key, Value::Image(42u32.to_le_bytes()))

Key(定位 relation fork size)

可读分段:00/0000067F/00000005/00004000/00/FFFFFFFF 逻辑 Key 转义/Display: 000000067F000000050000400000FFFFFFFF 逻辑 Key Hex: 000000067F000000050000400000FFFFFFFF Delta index Key Hex: 000000067F000000050000400000FFFFFFFF0000000000000100

Value(保存页数)

内层 Image 解码:42 内层 Image Hex:2A000000 Delta Value 长度:16B Delta Value Hex: 0000000000000000000000042A000000 分段: 00000000 -> Value::Image tag 0000000000000004 -> Image 长度 4 2A000000 -> u32 little-endian 42 delta blob 完整前缀:10(payload 长度 16)| 上述 16B

编码与使用

Key: spc/db/rel/fork + FFFFFFFF size sentinel -> 18B BE -> 追加 LSN Value:nblocks=42 -> u32 LE -> Value::Image 写入: relation create/extend/truncate 与受影响页在同一 modification 中维护 读取: get(size Key, LSN) -> Image -> get_u32_le 回表: 读取 relation page 前先查 size;越过 EOF 返回零页

3.3 relation block 7 的零页 Image

  • 逻辑输入:同一 relation 的 block7,写入 8192 个零字节,LSN0/100。这是 relation 扩展产生 gap 时当前生产路径实际使用的 Image。
  • 写入形式put(rel_block_key, Value::Image(ZERO_PAGE))

Key(定位一个 PostgreSQL 物理页)

可读分段:00/0000067F/00000005/00004000/00/00000007 逻辑 Key 转义/Display: 000000067F00000005000040000000000007 逻辑 Key Hex: 000000067F00000005000040000000000007 Delta index Key Hex: 000000067F000000050000400000000000070000000000000100

Value(保存完整 8KiB 页)

内层 Image:8192B,全 00 Delta Value 总长度:8204B Delta Value Hex(真实首尾;中间 8172B 00 省略): 首 32B: 0000000000000000000020000000000000000000000000000000000000000000 ... 尾 32B: 0000000000000000000000000000000000000000000000000000000000000000 分段: 00000000 -> Value::Image tag 0000000000002000 -> Image 长度 8192 00 × 8192 -> PostgreSQL 页 delta blob 4B 头:8000200C(payload 长度 8204,未压缩) 物理 blob 总长度:8208B

编码与使用

Key: relation 物理地址 + blkno 7 -> 18B BE -> 追加 LSN Value:ZERO_PAGE 8192B -> Value::Image envelope 写入: put_rel_page_image_zero -> serialized batch -> delta layer 读取: get(Key, requested LSN) 命中 Image 后直接返回,无 WAL redo 回表: 不需要;它本身就是 PostgreSQL heap/index/catalog/TOAST 等 relation 的物理页

3.4 visibility map 页的 ClearVisibilityMapFlags delta

  • 逻辑输入:同一 relation 的 VM fork2、block3;清除 heap block0x11对应位,旧 heap block 为空,flags=0x03,LSN0/100
  • 写入形式put(vm_page_key, Value::WalRecord(ClearVisibilityMapFlags{...}))

Key(定位 visibility map 物理页)

可读分段:00/0000067F/00000005/00004000/02/00000003 逻辑 Key 转义/Display: 000000067F00000005000040000200000003 逻辑 Key Hex: 000000067F00000005000040000200000003 Delta index Key Hex: 000000067F000000050000400002000000030000000000000100

Value(保存可重放页增量)

可读解码: Value::WalRecord( ClearVisibilityMapFlags { new_heap_blkno: Some(17), old_heap_blkno: None, flags: 3 } ) Delta Value 长度:15B Delta Value Hex: 000000010000000101000000110003 分段: 00000001 -> Value::WalRecord tag 00000001 -> ClearVisibilityMapFlags tag 01 00000011 -> Some(u32 BE 17) 00 -> None 03 -> flags delta blob 完整前缀:0F(payload 长度 15)| 上述 15B

编码与使用

Key: relation VM fork 地址 -> 18B BE -> 追加 LSN Value:专用 delta 字段 -> BE bincode enum 写入: WAL ingest 解析记录 -> put_rel_wal_record -> delta layer 读取: 从目标 LSN 向旧版本收集到 Image/will_init -> 按 LSN 正序应用 delta 回表: 不需要 SQL 回表;redo 需要该 VM Key 的旧 Image,且会按字段修改页

3.5 AUX 文件pg_logical/mappings/test1

  • 逻辑输入:路径pg_logical/mappings/test1,文件内容abc,LSN0/100
  • 写入形式put(aux_hash_key, Value::Image(aux_v1_bucket))

Key(定位 AUX hash bucket)

16B metadata 输入: 62 01 01 7F8B83D94F7081693471ABF91C 可读分段: 62/00000101/7F8B83D9/4F708169/34/71ABF91C 逻辑 Key 转义/Display: 62000001017F8B83D94F7081693471ABF91C 逻辑 Key Hex(通用 18B 形式): 62000001017F8B83D94F7081693471ABF91C Delta index Key Hex: 62000001017F8B83D94F7081693471ABF91C0000000000000100 分段: 62 -> AUX v2 prefix 0000 -> 16B metadata Key 展开到 18B 时的 field2 高位补零 01 01 -> pg_logical / mappings 分类 7F8B...F91C -> FNV-1a-128("test1") 的低 104 位

Value(保存完整路径以处理 hash bucket 与碰撞)

可读解码:[("pg_logical/mappings/test1", b"abc")] 内层 AUX payload 长度:37B Delta Value 长度:49B Delta Value Hex: 000000000000000000000025010000001970675F6C6F676963616C2F6D617070696E67732F746573743100000003616263 分段: 00000000 -> Value::Image tag 0000000000000025 -> Image 长度 37 01 -> AUX value format version 1 00000019 -> path 长度 25 7067...7431 -> UTF-8 path 00000003 -> content 长度 3 616263 -> "abc" delta blob 完整前缀:31(payload 长度 49)| 上述 49B

编码与使用

Key: 路径分类 + 文件名 hash -> 16B metadata Key -> 通用 18B Key -> 追加 LSN Value:version + 完整 path/content -> Value::Image 写入: 先 get(bucket),按完整 path 更新/删除,再整体重写该 bucket 读取: scan([62..63), LSN) -> 每个 Value 解码 -> 汇总完整路径 回表: 不需要;主定位依赖 Key,碰撞消歧依赖 Value 中完整 path

当前源码不存在独立 SQL 主键、唯一索引或非唯一二级索引 KV,因此没有伪造相应示例。PostgreSQL 的 B-tree/GIN/GiST 等索引页与示例 3 使用完全相同的 relation block Key/Value 格式。

4. Schema 如何保存

4.1 SQL Schema 与 Pageserver 物理元数据的边界

逻辑对象持久化状态KeyValue创建/修改/删除
tenant / shard / timeline不进入用户数据 KV不适用;位于目录、远端对象路径和 layer summary控制面 metadata/index JSON,不是本报告的 Value由 Pageserver 控制面维护
PostgreSQL database 目录独立 KV固定 DB directory Key整体 BE bincode map:(spcnode,dbnode)->relmap_exists新 DB 或 relmap 首次出现重写整个 map;drop 删除 map 项
SQL schema/namespace嵌入其他 Valuepg_namespace 等 catalog relation 的 block Key原始 catalog 页 Image/WAL deltaDDL 作为 catalog 页 WAL 更新
table / materialized view / sequence / TOAST relation物理 relation 独立成多组 KV;定义嵌入 catalog 页spcnode/dbnode/relnode/fork/blockrelation page Image/WAL delta;名字、owner 等定义在 catalog 页create/drop 改 relation directory、size 与 catalog pages
column、逻辑类型、nullable、default、generated嵌入 catalog/heap Value不形成字段级 Keypg_attribute、pg_type、pg_attrdef 等 relation 页字段变化只重写受影响页,不形成 Pageserver schema Value
primary key、unique/check/foreign key、index definition、predicate/include columns嵌入 catalog Value不形成定义级 Keypg_constraint、pg_index 等 catalog 页DDL 由 catalog 页 WAL 表示
普通/唯一/表达式/部分/覆盖/全文/空间索引索引主体是普通 relation block KVKey 不含索引列或唯一性,只含索引 relation 的 relnode/fork/blockPostgreSQL 索引页原始 bytesPostgreSQL 维护页;Pageserver 不判重、不解析索引项
relation directory v1独立 KV,默认每个(spcnode,dbnode)一个 Key整体HashSet<(relnode,forknum)>create/drop 会重写整个集合
relation existence v2可选独立稀疏 KV每个(spc,db,rel,fork)一个0x65Keyr表示存在;空 Value 表示 removed可选迁移时逐 relation 建 Key;drop 写空 Image
relation size独立版本化 KVrelation block 空间末尾,blknum=FFFFFFFF4B LEnblockscreate/extend/truncate 写新版本
relmap (pg_filenode.map)独立 KV(spc,db,0,0,0)文件原始 bytesput 重写完整 Value;drop 当前未实现
sequence/identity 当前值嵌入 relation pagesequence relation block KeyPostgreSQL sequence 页与普通 relation 页相同
权限、函数、视图定义、统计信息嵌入 catalog relation pages;部分运行统计可在 AUX无对象级 Keycatalog 页或 AUX 文件 bytes由对应 WAL/AUX 更新
object/OID allocator无 Pageserver allocator不适用PG control/catalog/SLRU 页中的状态由 PostgreSQL 产生并通过页/WAL 持久化
partition、placement、TTL、DDL job没有 Pageserver 独立 schema KV不适用PostgreSQL 自己的 catalog 页;Pageserver TTL/DDL job 不适用不适用

4.2 目录 Value 的重写粒度

源码事实

  • DB directory、relation directory v1、SLRU segment directory、two-phase directory 都把整个 map/set 放在一个 Image Value。
  • 这些集合内一个元素变化会重新序列化并写入完整新版本。
  • HashMap/HashSet 的非空元素迭代顺序不是 Key 排序协议;读取不能依赖 Value 内条目顺序。
  • relation directory v2 把一个 relation fork 拆成一个稀疏 KV,避免 v1 单 Value 随 relation 数量增长,但会增加 Key 数和 metadata 扫描项。

机制推导

  • v1 点查目录只需一个 Key,但目录越大,单项 DDL 的 Value 重写量越大。
  • v2 的创建/删除只改一个短 Value,代价是扫描、layer index 和版本项数量增加。

5. Data 如何保存

5.1 当前 Key space 全集

对象Key 布局Value 布局访问
DB directory`0000
relmap file`00spcdb
relation directory v1`00spcdb
relation block`00spcdb
relation size`00spcdb
SLRU directory`01kind0
SLRU block`01kind1
SLRU segment size`01kind1
two-phase directory`0200
two-phase file`0200
control file`0300
checkpoint`0300
AUX v1(兼容保留)`0300
relation existence v2`65spcdb
AUX v2 bucket`62class2Bhash104` 的 16B 设计,展开为 18B
replication origin`6300

0x61relation-size metadata prefix 和0x64DB-directory metadata prefix 在当前版本只保留常量,没有生产 Key 构造或写入。它们不能视为已实现格式。

5.2 relation 主数据

四种 fork 都显式进入 Key:

forknumforkPageserver Value
0main8KiB 页 Image 或 PostgreSQL WAL delta
1FSM8KiB 页 Image 或 WAL delta
2visibility map8KiB 页 Image、PG WAL delta或专用 VM delta
3init fork8KiB 页 Image 或 WAL delta;分片规则把它保留在 shard 0

同一个 relation fork 的 Key 范围是:

[00|spc|db|rel|fork|00000000, 00|spc|db|rel|(fork+1)|00000000)

该范围包含所有 block,并在末尾包含FFFFFFFFsize Key。普通点查先用 size Key 验证 EOF,再取 block Key。Pageserver 不知道该页是 heap tuple、B-tree internal node、GIN posting list、catalog tuple 还是 TOAST chunk。

5.3 所有 Value 类型与字段编码族

类型/变体Key 中编码Delta Value 中编码NULL/边界/状态
Value::Image(Bytes)无类型 tag`u32 tag=0u64 len
Value::WalRecord(Postgres)无类型 tag`Value tag=1record tag=0
ClearVisibilityMapFlags目标 VM 页在 Keyrecord tag=1;两个Option<u32>+u8 flagsOption 用 0/1 标记;当前生产
ClogSetCommitted目标 pg_xact 页在 Keyrecord tag=2;Vec<u32>+i64 timestampVec 为u64 count+ BE 元素;当前生产
ClogSetAborted目标 pg_xact 页在 Keyrecord tag=3;Vec<u32>当前生产
MultixactOffsetCreate目标 offsets 页在 Keyrecord tag=4;`mid:u32moff:u32`
MultixactMembersCreate目标 members 页在 Keyrecord tag=5;`moff:u32Vec<(xid,status)>`
AuxFile旧固定 AUX v1 Keyrecord tag=6;String path + Option Bytes当前源码没有生产构造者;兼容旧 Value
TruncateVisibilityMap目标 VM 页在 Keyrecord tag=7;两个usize当前生产
Test任意测试 Keytesting feature 下的 record tag=8非生产
relation/SLRU sizesize sentinel 在 KeyImage 内层u32 LE最大u32页数;无 NULL
replication origin LSNorigin ID 在 KeyImage 内层u64 BELSN=0表示 drop
AUX path/content分类/hash 在 KeyImage 内层版本 1、u32 BE长度和 bytes删除最后一项得到空内层 Value
SQL boolean/int/numeric/text/date/JSON/array/UUID/自定义类型等SQL 类型和值都不进入 Pageserver Key作为 PostgreSQL tuple/index page 的不透明 bytesSQL NULL bitmap、排序、collation、TOAST 由 PostgreSQL 页格式负责;全部共享 relation-page 编码族

这里没有独立 Pageserver SQL 类型注册表,也没有“每列 Value codec”。因此不能把 PostgreSQL tuple 内的类型编码冒充为 Pageserver KV Value 格式。

5.4 PostgreSQL 索引与 Pageserver 物理索引

索引含义KeyValue主记录定位符/唯一性
PostgreSQL primary/unique/non-unique B-tree索引 relation 的物理页 Key原始 B-tree 页 Image/WAL deltaTID、排序、NULL 与唯一性都在 PostgreSQL 索引页;Pageserver 不解析,查询仍由 PostgreSQL 回 heap
PostgreSQL hash/GIN/GiST/SP-GiST/BRIN对应索引 relation 的物理页 Key对应 AM 的原始页与上相同
PostgreSQL expression/partial/include index定义在 catalog 页;主体仍是索引 relation 页原始页predicate/expression/include 不进入 Pageserver Key
Pageserver delta layer B-tree`18B Key8B LSN`5BBlobRef
Pageserver image layer B-tree18B Key5B blob offset定位该 layer LSN 下的完整 Image

Delta B-tree 以(Key,LSN)字节序范围扫描。读取一个 Key 的目标版本时,从Key|LSN下界开始遍历并过滤请求 LSN 区间;遍历层次时从新到旧收集,Value redo 时再反转为 LSN 正序。

5.5 版本、删除、墓碑与分片

版本

  • LSN 是 Pageserver 的 MVCC 版本轴,不是 SQL transaction ID 后缀。
  • 同一 Key/LSN 在进入内存 index 时保留最后一次写入;早先追加的 raw bytes 可留在 ephemeral file,但不再被索引。
  • Image 或will_init=truedelta 截断对更老版本的依赖。
  • Image layer 把一个 LSN 的完整状态物化,降低后续必须重放的历史链长度;这是机制性质,不代表本文提供了性能基准。

删除

  • Dense relation/SLRU/database/two-phase range delete 最终调用的 in-memory tombstone 写入当前是 no-op。逻辑删除依赖 directory/size 新版本让旧 Key 不再可达;源码明确承认旧物理存储暂时泄漏。
  • relation directory v2 的Value空 bytes 是 sparse tombstone;r是存在标记。
  • replication origin drop 的Value是 8B 全零LSN::INVALID;读取扫描跳过它。祖先 detach 路径还可能产生 sparse 空 Image。
  • AUX 删除会重写 bucket;bucket 无文件时内层Value为空。Key 仍可存在,不等同 SQL NULL。
  • 没有用户数据 TTL。

分片与 namespace

  • Tenant/shard/timeline 不重复编码在 18B Key,而是由本地路径、远端对象路径、layer 文件名及 summary 隔离。
  • relation 普通页按hash(relnode, block/stripe_size)分布;默认 stripe 是 2048 个 8KiB 页,即 16MiB。
  • init fork 和非 relation page 的特殊对象落在 shard 0;relation size 等部分 metadata 可全 shard 保留。
  • sharding 改变 Key 放在哪个 layer 集合,不改变 18B Key 或 Value bytes。

6. KV 数据库的启示

可借鉴设计适用访问模式直接收益生效前提与代价
固定宽度、BE 复合 Key物理对象点查、连续 block 扫描字节序即字段数值序;范围上下界简单字段预算固定;tablespace 压缩限制扩展性
Key | LSNdelta 索引多版本 point lookup、PITR同一 Key 的版本相邻且按时间排序历史层多时读放大,需要 compaction/image
Image + redo delta 双 Value页级 WAL 系统可以选择写完整页或小 delta;will_init 明确历史截断点读取可能需要多条 delta 和 WAL redo
LSN 移到 image layer header同一快照覆盖很多 Keyimage index Key 从 26B 降到 18B一个 layer 只能代表一个 materialization LSN
relation size 放在 block range 末尾extend/truncate 与尾页访问同一 fork 的 block 与 size Key 相邻、单范围覆盖FFFFFFFF被保留,不能作为普通 block
稀疏 metadata Key space可选对象、扫描目录missing/empty 可自然表示不存在empty Value 语义必须按对象区分;扫描仅限 metadata
hash Key + 完整路径 Value路径较长、需要固定 KeyKey 固定 18B;Value 可处理 hash collision更新 collision bucket 要读改写整个 Value;不支持按任意路径字典序扫描
immutable layer + 内嵌 B-tree本地文件与对象存储共用格式layer 可原样上传;不依赖外部 KV 引擎compaction、GC、下载和多 layer 选择由 Pageserver 自己承担
物理页作为 Value托管完整 PostgreSQL 语义无需复制 SQL 类型/索引 codec,能覆盖扩展类型无法用 Pageserver Key 做 SQL 行级/索引值级查询或局部列更新
小目录整体 Value / 大目录拆 Key元数据规模分层可在点查次数与单项重写量之间选择需要迁移状态和双写/双读兼容逻辑

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询