postgresql单条insert默认比mysql快,实测延迟仅0.2ms(mysql为0.8ms),高并发吞吐可达其4.9倍;若变慢,主因是fsync行为、事务策略或客户端未复用连接/预编译语句。

PostgreSQL 执行单条 INSERT 并不比 MySQL 慢——实测数据显示,在默认配置下,PG 的写入延迟是 MySQL 的 1/4(0.2ms vs 0.8ms),高并发写吞吐甚至可达 MySQL 的 4.9 倍。如果你观察到 PG 插入更慢,问题几乎一定出在 fsync 行为、事务提交策略或客户端使用方式上,而不是数据库本身写入引擎的固有缺陷。
为什么改了 synchronous_commit = off 还没变快?
这个参数只控制 WAL 日志是否等待刷盘完成才返回成功,但它不解决以下真实瓶颈:
-
synchronous_commit = off后,WAL 仍会异步写入 page cache,但若内核 writeback 线程积压(如vm.dirty_ratio高、磁盘 I/O 拥塞),实际落盘延迟仍可能达数百毫秒 - 客户端未复用
PREPARE语句,每次INSERT都触发语法解析 + 权限检查 + 计划生成,这部分开销在 PG 中比 MySQL 更重(尤其带复杂表达式时) - 连接未复用:短连接导致 TCP 握手 + SSL 协商 + PostgreSQL 认证(SASL/SCRAM)重复执行,耗时常超 SQL 本身
- 表上有过多二级索引,而
synchronous_commit不影响索引页分裂或缓冲区淘汰等本地操作
fsync 调用太频繁时,PostgreSQL 性能掉在哪?
PG 默认启用 fsync = on 和 synchronous_commit = on,意味着每次 COMMIT 都会触发一次 fsync() 系统调用。这不是“慢”,而是“确定性等待”:
- SSD 上单次
fsync实测延迟通常在 0.3–1.5ms,看似不高,但乘以每秒上千次提交,就成了吞吐瓶颈 -
fsync会阻塞当前 backend 进程,无法重叠 I/O 与计算;而 MySQL 的innodb_flush_log_at_trx_commit = 1同样有此行为,但 PG 的 WAL 追加写机制使其更容易被 I/O 队列压垮 - 若文件系统挂载为
data=ordered(ext4 默认),fsync还需等待关联数据页刷盘,进一步延长等待 - 不要只调
synchronous_commit:还要确认wal_sync_method是否为fdatasync(推荐),而非更重的fsync或open_sync
MySQL 的 innodb_flush_log_at_trx_commit = 2 能直接套到 PG 吗?
不能。两者的日志同步语义不同:
- MySQL 设置为
2时,redo log 写入 OS 缓冲区即返回,最多丢失 1 秒数据;但 PG 的synchronous_commit = off是把 WAL 写入 page cache 后就返回,**不保证任何时间窗口内的持久性**,崩溃后可能丢失任意未刷盘的 WAL 段 - MySQL 的
2是“秒级容忍”,PG 的off是“尽力而为”,风险等级更高——尤其当主从复制依赖 WAL 流式传输时,off可能导致从库数据滞后甚至断裂 - 真正对标 MySQL
2的 PG 配置是:synchronous_commit = remote_write(需启用synchronous_standby_names)+wal_level = replica,此时至少一个备库收到 WAL 才返回 - 如果只是单机开发环境,可设
commit_delay = 10000(单位微秒)+commit_siblings = 5,让多个事务攒批触发一次fsync,比单纯关synchronous_commit更可控
最易被忽略的一点:PG 的 fsync 延迟不是孤立的,它和 checkpoint_timeout、max_wal_size、底层存储的 queue depth、甚至 NVMe 的 firmware 刷盘策略都耦合在一起。调一个参数没用,必须看 pg_stat_bgwriter 里 checkpoints_timed 和 buffers_checkpoint 是否异常飙升——那说明检查点正在抢 I/O,此时再压 INSERT 只会让 fsync 更卡。











