Skip to the content.

自动审计的 PostgreSQL 性能记录

2026-10-15,在指定 PostgreSQL 测试环境比较普通上下文、审计关闭和审计开启。功能与事务验证通过,性能目标未通过。 当前数据不能支持“开启审计后普通 CRUD 吞吐/P95 损失不超过 10%”或“无审计变化时不超过 5%”的结论。

测量客户端为 Windows 10.0.19045、.NET 10.0.13、6 个逻辑处理器;服务器 PostgreSQL 16.15,通过局域网连接。服务器 CPU、磁盘和同时运行的其他业务负载未测定。指定测试库最初不存在,因此显式初始化了该专用库;测试结束只删除每轮创建的临时 schema,数据库保留。连接串与凭据没有进入报告。

最终版本的定向比较

最终版本默认生成 UUID v7 操作/明细 ID。下面每种模式均为并发 4、每线程预热 24 次,测量 3 轮,每轮每线程 96 次,共 1,152 次。三种模式轮换执行顺序,业务查询与显式事务相同。

场景/模式 ops/s P50 ms P95 ms P99 ms 近似分配 bytes/op
单实体/普通上下文 480.7 3.41 34.55 77.14 65,862
单实体/审计关闭 485.1 3.50 25.41 74.52 73,884
单实体/审计开启 190.9 16.95 72.11 101.48 94,107
三表四实体/普通上下文 199.5 5.31 79.74 146.29 99,380
三表四实体/审计关闭 261.6 4.66 42.13 192.97 107,502
三表四实体/审计开启 88.6 33.45 115.77 229.28 176,860

以同一审计基类的开关比较,单实体开启后吞吐下降约 60.7%,P95 增加约 183.8%;三表四实体吞吐下降约 66.1%,P95 增加约 174.8%。普通上下文是补充基线,用来观察接入基类本身的成本;它与关闭模式的尾延迟也有明显差异,说明环境存在波动,不宜给这些百分比作精确的长期承诺。原始汇总见 UUID v7 定向结果。

耗时在哪里

场景/模式 到 SavingChanges 回调平均 ms SaveChanges 平均 ms Commit 平均 ms
单实体/审计关闭 <0.01 1.89 4.53
单实体/审计开启 0.07 2.31 16.83
三表四实体/审计关闭 <0.01 1.85 11.43
三表四实体/审计开启 0.07 2.54 40.02

开启模式在 SavingChanges 回调前完成变更检测、差异序列化和审计实体附加,因此第一列可以观察这部分采集成本。普通 EF 的检测发生在该回调之后,不能直接把第一列相减作为两种实现的纯 CPU 差异。这里的平均数也不代表采集阶段的 P95。

单实体每操作 2 次 EF 命令执行,三表场景 3 次,三种模式相同。这不意味着写入量相同:Npgsql 在一个保存批次中执行业务及审计语句。单实体多一个审计 INSERT;三表场景多四个,且每条明细有主键和两个查询索引。每个测量块均校验实际新增审计条数,不能通过漏写来降低成本。

服务器使用 fsync=on、full_page_writes=on、synchronous_commit=on、wal_sync_method=fdatasync,没有配置同步 standby 名称。测试未修改这些设置。观测到的主要增量集中在提交阶段,符合增加持久写入后的成本特征;但 track_wal_io_timing=off,也没有服务器磁盘和复制过程的观测,尚不能把具体根因归结为某块磁盘或某个 PostgreSQL 参数。

UUID v7 改善键的时间局部性,但这轮结果仍未达到目标。两轮之间存在环境变化,不能仅凭单实体吞吐上升就断言收益完全来自 ID 格式。仍保留同事务、完整选定字段和持久化语义,没有使用异步审计、无日志表或关闭同步提交来换取通过。

完整场景的诊断轮

下面是 UUID v4 版本的耗时分解轮,覆盖无变化、未选字段、单实体、多表和跟踪 1,000 条实体。它用于诊断,不代表最终 UUID v7 版本已对全部场景重新验收。每项每模式样本数:并发 1 为 288,并发 4 为 1,152。

场景 并发 普通 ops/s / P95 ms 关闭 ops/s / P95 ms 开启 ops/s / P95 ms
无变化 1 316.7 / 12.06 430.1 / 6.72 375.3 / 12.17
无变化 4 1753.2 / 4.81 1161.1 / 8.26 1306.2 / 6.15
未选字段 1 229.9 / 11.32 202.4 / 13.74 185.8 / 17.46
未选字段 4 671.2 / 24.18 621.9 / 24.62 484.3 / 33.26
单实体 1 265.0 / 8.21 217.9 / 16.22 142.0 / 26.22
单实体 4 460.1 / 47.60 473.6 / 27.43 142.5 / 99.38
三表四实体 1 128.2 / 24.44 91.7 / 36.72 33.8 / 105.53
三表四实体 4 257.4 / 71.95 236.3 / 65.10 69.7 / 184.48
跟踪 1,000 条改一条 1 145.5 / 16.18 114.4 / 20.33 66.7 / 55.80
跟踪 1,000 条改一条 4 180.1 / 79.04 271.3 / 31.33 132.8 / 70.30

跟踪 1,000 条时,开启模式在保存回调前平均约 0.82ms(并发 1)/1.99ms(并发 4),大部分实体未发生变化也有检查成本。业务只需要修改一条时,应避免为了本次操作跟踪无关的大量实体;这项场景仍保留,用来暴露接入成本。原始汇总见 完整诊断结果。

证据范围与后续验收

PostgreSQL 上验证了三表四实体一起提交,以及外层回滚同时撤销业务和审计;SQLite 回归还覆盖缺失身份、超限、取消、保存回调失败、约束失败重试、附加实体原值未知和同步增删改。Lab API 验证覆盖多表效果、同操作归组及用户隔离。事务正确性不等于性能达标。

下一次性能验收应先同时记录服务器 WAL 同步/磁盘延迟和其他负载,确定提交成本来源,再决定索引、批量事务大小或服务器配置的取舍。改变事务批量大小必须同时检查业务延迟与锁持有时间。当前实现适合继续功能 review;高 TPS 场景的性能验收仍未完成,不能按已达标交付生产容量承诺。复现参数和测量边界见 基准程序 README。