# 同步 I/O 基准（v0.6.0）

测量日期：2026-10-04。以 `python tools/benchmark_io.py` 重建数据并运行，原始结果默认写 `_build/io-benchmark.json`。每个命令在新 Node 进程中执行一次；固定 4096 字节页、普通表及文本索引、`k` 对应 8 位十进制文本加 50 个“中”，缓存 64 个 4096 字节块。扫描只访问表根 2，全局检查使用 summary-json，WAL 打开只请求 header。SQLite 创建并关闭数据库前保存 db/WAL 配对副本，闭库 checkpoint 后的数据库用于前两项。

环境：Windows-11-10.0.26200-SP0；Python 3.13.2 / SQLite 3.45.3；Node v22.14.0；Moon 0.1.20260920 / moonc v0.10.14+7d59c7ec9。使用 debug JS 构建、本机文件缓存；不是跨机器性能承诺，首次冷读与重复测量可能不同。

| 行数 | 操作 | db / WAL 字节 | 读取次数 | 请求字节 | 峰值 RSS MiB | 秒 |
| --- | --- | --- | --- | --- | --- | --- |
| 1000 | scan | 376832 / 395552 | 44 | 180224 | 41.12 | 0.0390 |
| 1000 | inspect | 376832 / 395552 | 92 | 376832 | 43.52 | 0.0534 |
| 1000 | wal_open | 376832 / 395552 | 99 | 399748 | 38.89 | 0.0239 |
| 5000 | scan | 1843200 / 1870512 | 211 | 864256 | 44.70 | 0.0691 |
| 5000 | inspect | 1843200 / 1870512 | 450 | 1843200 | 48.93 | 0.1162 |
| 5000 | wal_open | 1843200 / 1870512 | 457 | 1874708 | 40.66 | 0.0325 |
| 20000 | scan | 7340032 / 7399552 | 838 | 3432448 | 46.06 | 0.1326 |
| 20000 | inspect | 7340032 / 7399552 | 1792 | 7340032 | 55.54 | 0.2368 |
| 20000 | wal_open | 7340032 / 7399552 | 1799 | 7403748 | 42.50 | 0.0641 |

扫描与全局检查单次最大读取均为 4096 字节，WAL 打开为 4120 字节（帧头加页面）；缓存内容预算为 256 KiB。RSS 是 Node 整个进程的 OS 峰值，包含运行时、解析状态、报告及序列化，不能当作缓存大小或精确库堆占用。测量命令的耗时包含加载检查器、打开文件及输出，通常 Node 启动成本占小样本较大比例。

扫描 I/O 随被访问的 B-tree/overflow 页增长，保留 visited 集合和深度栈；全局检查需要访问所有对象并保存页归属/未知列表，读取和状态都随逻辑页数增长。WAL 打开需顺序扫描完整连续有效日志，读取随有效帧数增长，保存帧元数据及每页最新版本索引；重复更新同页仍增加帧报告，但不同比例增加覆盖索引。缓存为独立固定预算；预算耗尽返回错误或 Incomplete，不能将早期快照当作最新提交。

范围验收的 2 GiB 稀疏输入只读取页 1 和末页，共两次 I/O / 4608 字节；全局检查因为默认页数预算预检返回 Incomplete，不扫描未初始化中间页。该证据证明寻址及按需 I/O，不代表本机已完成 2 GiB 合法数据库全库检查。

## 少量页反复更新

同一次运行另建 8192 字节主文件，8 行各 128 字节 BLOB；关闭自动 checkpoint、先 truncate checkpoint，然后每事务更新同一页内的两行。分别保存累计 100/1000/5000 次事务后的静态 db/WAL 副本；独立解析原始帧页号，核对最后两行的值与 SQLite 一致。每组在新 Node 进程打开范围快照并读取 header。

| 事务/帧数 | 唯一覆盖页 | WAL 字节 | 读取次数 | 请求字节 | 峰值 RSS MiB | 秒 |
| --- | --- | --- | --- | --- | --- | --- |
| 100 | 1 | 412032 | 102 | 416128 | 38.74 | 0.0223 |
| 1000 | 1 | 4120032 | 1002 | 4124128 | 42.18 | 0.0435 |
| 5000 | 1 | 20600032 | 5002 | 20604128 | 44.32 | 0.1268 |

单次请求最大 4120 字节。帧报告随 100–5000 帧增长，覆盖索引始终只有 1 个页；实际进程 RSS 同时受运行时和 GC 影响，不据此换算每帧精确成本。该基准分别报告帧数、唯一覆盖页、请求字节和 OS 峰值内存，CI 校验结构及快照正确性，不以时间或 RSS 波动作为失败条件。可用 `--wal-updates 100,1000,5000` 重复运行。

## 大数据边界验收

`python tools/verify_large_payload.py` 对 72663040 字节合法数据库验证累计 72094000 字节 payload 的扫描和全局检查：默认明确受限，提高预算后完整完成；17 MiB 单条记录另验证单条预算。这是合法数据的完整检查证据，不是吞吐基准。

`node tools/verify_wide_wal.cjs` 按需生成 2148335672 字节有效虚拟 WAL，32769 帧均通过累计 checksum，实际读取最新覆盖页的偏移为 2148270136。该输入不会在内存或磁盘完整分配；JS 扩展验收独立于四后端的高位覆盖索引边界回归。最大常规全库性能样本仍约 7 MiB，上述边界证据不扩展为任意规模吞吐承诺。

完整内存与支持边界见[范围源契约](range-source.md)。


## v0.8.0 与正式 v0.7.0 同输入比较

`python tools/benchmark_compatibility.py` 从正式提交 `8a3a4c79ecd54c893604839f9136081289b8f21b` 解出旧版并构建，然后让两个 CLI 读取同一组静态 db/WAL 文件；工具链、SQLite、Node、缓存配置和数据生成相同。完整环境与两组测量保存在 `_build/compatibility-benchmark.json`，CI 两个工具链通道均保存该证据。

2026-10-06 本机固定环境（Node 22.14.0、Python 3.13.2、SQLite 3.45.3）测得 12 个场景的读取次数、总字节和最大读取块与 v0.7.0 完全一致。以下是一次顺序测量；RSS 是进程峰值，时间包含 CLI 启动，不作统计显著性或所有机器的耗时保证。

| 场景 | 读取次数 / 字节 | 当前 / v0.7.0 秒数 | 当前 / v0.7.0 峰值 RSS 字节 |
| --- | --- | --- | --- |
| 20000 行扫描 | 838 / 3432448 | 0.1367 / 0.1361 | 48803840 / 48893952 |
| 20000 行全库检查 | 1792 / 7340032 | 0.2376 / 0.2449 | 59265024 / 59318272 |
| 20000 行 WAL 打开 | 1799 / 7403748 | 0.0622 / 0.0632 | 45293568 / 45125632 |
| 5000 次更新同一覆盖页 | 5002 / 20604128 | 0.1262 / 0.1254 | 47235072 / 47673344 |

普通读取块最多 4096 字节，WAL 帧块最多 4120 字节。该对照证明本次目录和注释整理在固定输入上的 I/O 成本保持，不声称全库检查或 WAL 索引为常量内存。原有超过 64 MiB payload、高位 WAL 和静态数据正确性检查仍单独运行，不以性能记录代替它们。
