当前位置: 首页 > news >正文

PostgreSQL因为A/B switch以及group表过多导致WAL full的情况讨论

背景

我们用的是pgsql数据库,我们系统设计是一个customer group一个逻辑分组,然后一个分组有15个表左右,也就是detail_tableA_groupA,detail_tableB_groupA......然后customer group有很多,有500个,那么一个customer15个表,那就有7500个表,导入的时候我们已经使用A/B table/view switch,这样就会导致有15000个表,每次都是执行导入a表或者b表,每次导入都是整表全量导入,经常导致WAL文件满然后数据库down掉。DBA建议我们分不同schema,这样就可以把500个group,15000个表分为约10个schema,每个schema约1500个表,请问这样合理吗,是否会减少WAL full的情况。

解读

Powered by Moshow郑锴@https://zhengkai.blog.csdn.net/

结论先说

  • 把 500 个 group(≈15,000 张表含 A/B)拆到 10 个 schema,主要是“管理上的整理”,几乎不会减少 WAL 产出,也不能从根本上避免 WAL 填满。WAL 的体量取决于你的“写入量、索引维护、检查点/归档/复制配置、并发度”,与表分在哪个 schema 关系不大。

  • 你们的“按组整表全量 + A/B 切换”的模式本身会在短时间内制造巨量 WAL。如果并发导入多个组、或归档/复制滞后,就很容易把 pg_wal 盘打满。

为什么会 WAL 满

  • 导入量大且集中:整表全量 COPY/INSERT + 同步维护索引,会产生接近“数据大小 ×(1~多)倍”的 WAL(索引构建也要写 WAL)。

  • 并发导入:同一时间跑多个组,WAL 生成速率叠加,超过归档/回收能力。

  • 检查点与全页写:频繁 checkpoint 会触发更多 full-page images;设置不当会放大 WAL。

  • 归档/复制滞后:archive_command 失败、或有复制槽/下游滞后,会导致 WAL 无法回收,pg_wal 迅速被撑满。

  • A/B 策略的额外成本:新表建索引、写入统计与元数据变更,都会追加 WAL;表越多,目录开销也更大。

该不该分 schema?

  • 可以分:提升可读性、权限隔离、运维分组、减少一个 schema 下目录项过多的管理麻烦。

  • 不要指望它减 WAL:WAL 是“集群级”的日志,写入多少由变更量与参数决定,与 schema 分布无关。

  • 可能的边际好处:轻微缓解系统目录热度/锁竞争,但对 WAL 体量影响可以忽略。

优先级最高的改造与参数(按效果排序)

  1. 架构/流程层面降峰值

  • 限制并发导入的组数(例如同一时刻 ≤N 个组),把峰值 WAL 速率压下来。

  • 分批提交:一口气整表导入很猛,改为“分块 COPY、按块提交”(找到你们系统在“提交次数”和“单次事务大小”之间的平衡)。

  • 先 TRUNCATE 后 COPY:如果目标是全量覆盖,优先使用 TRUNCATE(WAL 极少),而不是 DELETE;随后 COPY 裸表再建索引。

  • 导入期间 synchronous_commit=off(会话级):不减 WAL 体积,但显著减 fsync 压力,提升吞吐,缓解堆积。

  • 先导数据、后建索引:对新表或被 TRUNCATE 的表,先 COPY,再建索引;比边写边维护索引的 WAL 更低。

  1. 用“分区交换”替代“表 A/B 切换”

  • 把每类明细表收敛为“15 个父表”,按 group_id 做 LIST/RANGE 分区(500 个分区/父表)。

  • 对需要全量刷新的 group:

    • 新建“独立同构表”,COPY 数据、建索引、ANALYZE;

    • 在同一事务内执行 ALTER TABLE … ATTACH PARTITION 把它“挂为该组的新分区”,再 DETACH+DROP 旧分区。

  • ATTACH/DETACH 属于元数据级别操作,数据不搬迁,WAL 极小;命名稳定、统计信息友好、计划器可用。

  • 注意:要满足分区约束检查;目标表需为 LOGGED;大表验证会扫描但不会产生成比例 WAL。

  1. 降低 WAL 产出与冲击的技巧

  • wal_compression=on:显著减少 full-page images 的体积。

  • 提高 checkpoint_timeout、max_wal_size,checkpoint_completion_target≈0.9:减少频繁 checkpoint 带来的 FPI 洪峰。

  • (可选、谨慎)导入窗口内关闭 full_page_writes:能大幅减 WAL,但崩溃后需依赖干净检查点;如果没有严格高可用/恢复要求且在维护窗内,才考虑。

  • (若无任何复制/归档需求)wal_level=minimal + COPY FREEZE 在维护窗口进行:对“新建且空表”的 COPY 可最小化 WAL,显著降压;需要重启改集群级参数,慎用。

  • UNLOGGED 作为中间落地表:加载几乎不记 WAL;然后批量 INSERT/CTAS 进正式表(仍会记 WAL,但可错峰/分组推进)。注意 UNLOGGED 崩溃后会被清空。

  1. 让 WAL 有地儿去

  • 增大 pg_wal 所在盘容量或迁移到更大/更快卷

  • 确保归档/复制健康:不要让 archive_command 失败;检查是否有落后的 replication slot 长期占坑;监控 slot 延迟并按需丢弃无主的槽。

  • 合理的 autovacuum/analyze:避免导入后长时间不做 ANALYZE 造成计划不稳定、重复大动作。

常用方案对比🌟

方案/设置对 WAL 体积的影响风险/注意事项适用场景
限制导入并发 + 分批提交直接降峰值速率需要压测找到最佳批量大小任何场景
TRUNCATE + COPY + 后建索引明显降低需要停写窗口全量覆盖
分区交换(ATTACH/DETACH)数据不搬迁,WAL 很小需要分区化改造需要 A/B 效果且稳定名
wal_compression=on降低 FPI 体积CPU 略增通用、推荐
提高 max_wal_size/检查点参数降低 FPI 次数/峰值占用更多磁盘磁盘富余
synchronous_commit=off(会话)不减体积,提吞吐崩溃可能丢最近事务可接受轻微数据回滚
wal_level=minimal + COPY FREEZE可大幅降低要无复制;需重启;严格条件维护窗口批量导入
UNLOGGED 中转中转不记 WAL崩溃丢中转表;最终写仍记 WAL想把压力错峰

一个可执行的导入流程范式(推荐)

  • 将 15 张“父表”按 group_id 做分区(每父表 500 分区)。

  • 对某 group 全量刷新:

    1. 在同构 schema 下创建“新数据表”(LOGGED),不建索引;

    2. 会话设置 synchronous_commit=off;COPY 数据(满足条件时可用 COPY FREEZE);

    3. 建索引(提高 maintenance_work_mem)、ANALYZE;

    4. BEGIN;ALTER TABLE 父表 ATTACH PARTITION 新表(带约束验证);DETACH 旧分区并 DROP;COMMIT。

  • 全流程 WAL 主要集中在“COPY + 建索引”,交换本身 WAL 极少;通过限制并发 + 分批 COPY,整体峰值可控。

关于你们当前 A/B 表

  • 如果暂不重构为分区:也尽量改为“TRUNCATE 目标表 + COPY + 后建索引”的一次性替换,而不是维护两套 A/B 并频繁重建索引。

  • 若坚持 A/B:考虑把“新表加载”阶段用 UNLOGGED,完成后在低峰期 ALTER SET LOGGED(注意这一步会重写表并产生日志,需评估窗口)。

我建议你们先落地的 5 条

  1. 立刻开启 wal_compression,并把 max_wal_size、checkpoint_timeout、checkpoint_completion_target 调到更保守的值。

  2. 检查 replication slots 与归档是否有滞后/失败,确保 WAL 能被及时回收。

  3. 把导入并发控制在一个稳态上限(例如 2–4 个组同时导),并把单次事务控制在“几百万行”级别。

  4. 改导入流程为“TRUNCATE + COPY + 后建索引 + ANALYZE”。

  5. 中期推进“分区 + 分区交换”替代“表级 A/B 切换”。

需要一点关键信息(好给你更具体的参数)

  • PostgreSQL 版本号?是否有物理/逻辑复制、归档?

  • 单表数据量与索引规模(行数/GB)大致范围?

  • 现在导入的并发度、多长时间跑完一次全量?

  • pg_wal 目录磁盘大小、当前 max_wal_size 与 checkpoint 参数?

附录

 Powered by Moshow郑锴@https://zhengkai.blog.csdn.net/

synchronous_commit=off(会话)

在 PostgreSQL 中设置 synchronous_commit=off(会话级)是一个非常实用的性能优化手段,尤其适用于你们这种“批量导入数据”的场景。下面我来详细解释它的作用和影响:

🚀 它的作用是什么?

当你设置 synchronous_commit=off事务提交时不会等待 WAL 写入磁盘(fsync)完成,而是直接返回成功给客户端。这意味着:

  • 事务提交更快:因为省去了等待磁盘刷写的时间。

  • 吞吐量显著提升:尤其在大量 INSERT/COPY 的场景下,可以提高导入速度 2~10 倍,甚至更多。

  • WAL 仍然会生成:只是写入是异步的,由后台进程负责 flush。

📉 有什么副作用?

  • 可能丢数据:如果数据库崩溃(如断电、kill -9),最近提交但尚未写入磁盘的事务可能会丢失。

  • 不会影响事务一致性:不会出现“部分提交”;要么整个事务丢失,要么完整保留。

  • 不建议用于关键业务写入:适合用于“可重导入”的数据,比如你们的全量导入流程。

✅ 适用场景

场景是否推荐使用 synchronous_commit=off
批量导入(COPY/INSERT)✅ 非常推荐
ETL 中间表写入✅ 推荐
日志类、缓存类表✅ 推荐
订单、交易类表❌ 不建议
需要强一致性场景❌ 不建议

🛠 如何设置(会话级)

你可以在导入脚本或连接后执行:

sql

SET synchronous_commit TO OFF;

或者在连接字符串中设置:

postgresql://user:pass@host/dbname?options=-c%20synchronous_commit=off

设置后只影响当前连接,不会影响其他会话。

🧠 总结一句话

synchronous_commit=off 是“牺牲一点点崩溃安全性,换取巨大导入性能”的利器。只要你导入的数据可以重做,它就是你最值得用的参数之一。

如果你想进一步压榨导入性能,我还可以帮你搭配其他参数,比如 wal_writer_delaycommit_delaymaintenance_work_mem 等,打造一套“极速导入配置”。要不要我帮你配一套?

wal_compression=on

wal_compression=on 是 PostgreSQL 中一个非常实用的参数,尤其在你进行大量写入或批量导入时,它可以显著减少 WAL(Write-Ahead Logging)日志的体积,从而提升整体性能。下面我来详细拆解它的作用和适用场景:

🧩 它到底做了什么?

当你设置 wal_compression=on,PostgreSQL 会尝试压缩那些写入 WAL 的数据块,尤其是那些因为 UPDATECOPY 操作而触发的 full-page writes(完整页写入)。

  • 默认情况下,每次修改数据页时,PostgreSQL 会把整个数据页写入 WAL,以确保崩溃恢复时能还原。

  • 如果这些页之间变化不大,压缩就能显著减少 WAL 的体积。

  • 使用的是 pglz 压缩算法(轻量级、低 CPU 消耗)。

📉 有什么好处?

  • 减少 WAL 文件大小:尤其在高频写入场景下,WAL 体积可以减少 30%~70%。

  • 降低磁盘 I/O 压力:WAL 写入更少,磁盘负担更轻。

  • 提升性能:在某些场景下,尤其是 SSD 或网络存储,性能提升非常明显。

  • 更快的备份与复制:WAL 更小,流复制和归档也更高效。

⚠️ 有什么代价?

  • 略微增加 CPU 使用率:因为需要进行压缩运算,但通常非常轻微。

  • 对 INSERT 大量新数据影响较小:因为 INSERT 通常不触发 full-page writes,压缩效果有限。

  • 对 UPDATE/COPY 更有效:尤其是修改已有数据页时。

✅ 适用场景

场景是否推荐开启 wal_compression=on
大量 UPDATE 操作✅ 非常推荐
批量 COPY 导入(更新旧数据)✅ 推荐
高并发写入系统✅ 推荐
INSERT 新数据为主⚠️ 效果有限
CPU 紧张场景❌ 需评估是否值得开启

🛠 如何设置

你可以在 postgresql.conf 中设置:

conf

wal_compression = on

或者在运行时通过 SQL 设置(需超级用户):

sql

ALTER SYSTEM SET wal_compression = 'on';
SELECT pg_reload_conf();

🧠 总结一句话

wal_compression=on 是一个“用少量 CPU 换大量磁盘空间”的优化选项,在写入密集型场景中非常值得开启,尤其是你在做批量导入或频繁更新时。

如果你正在调优导入性能,我可以帮你搭配一整套参数组合,比如 synchronous_commit=offwal_writer_delaycommit_delaycheckpoint_timeout 等,打造一个“极速导入模式”。要不要我帮你配一套?

PostgreSQL 导入优化参数配置

参数推荐值作用说明
synchronous_commitoff提交事务不等待 WAL 写入磁盘,显著加快写入速度
wal_compressionon压缩 WAL 中的 full-page writes,减少磁盘 I/O
wal_writer_delay200msWAL 写入延迟,减少频繁刷盘(默认是 200ms,可视情况调高)
commit_delay10000(单位微秒)提交延迟,允许多个事务聚合写入 WAL,提高效率
checkpoint_timeout30min延长检查点间隔,减少导入期间的磁盘压力(默认 5min)
checkpoint_completion_target0.9检查点更平滑地进行,避免 I/O 峰值
max_wal_size2GB 或更高增加 WAL 空间,避免频繁触发 checkpoint
maintenance_work_mem512MB 或更高COPY 导入时用于索引构建、排序等操作,提升效率

✅ 会话级设置(导入脚本中执行)

SET synchronous_commit TO OFF;

✅ 系统级设置(postgresql.conf

wal_compression = on
wal_writer_delay = 200ms
commit_delay = 10000
checkpoint_timeout = 30min
checkpoint_completion_target = 0.9
max_wal_size = 2GB
maintenance_work_mem = 512MB

⚠️ 修改这些参数后需重启 PostgreSQL 服务才能生效。

🚀 COPY 导入技巧加持

  • 使用 COPY ... FROM STDIN WITH (FORMAT csv) 而非 INSERT。

  • 禁用索引和约束,导入后再启用。

  • 使用事务包裹多个 COPY 操作,减少 commit 次数。

  • 导入完成后手动执行 CHECKPOINT,确保数据落盘。

http://www.dtcms.com/a/325153.html

相关文章:

  • 托福单词词组积累 2025-08-10
  • 大模型 MCP服务案例详细讲解
  • 线程池的核心线程数与最大线程数怎么设置
  • NVIDIA Jetson AGX Orin 全景解析——边缘计算的高性能选择
  • 攻击实验(ARP欺骗、MAC洪范、TCP SYN Flood攻击、DNS欺骗、DHCP饿死)
  • VGG改进(1):基于Global Attention模块的详解与实战
  • RL代码实践 02——策略迭代
  • ai生成完成后语音通知
  • Starlink卫星终端对星策略是终端自主执行的还是网管中心调度的?
  • 如何部署图床系统 完整教程
  • python魔法属性__module__与__class__介绍
  • 学习numpy详解
  • Shell脚本-其他变量定义
  • 全面了解机器语言之kmeans
  • Redis缓存穿透、缓存击穿、缓存雪崩
  • Mock与Stub
  • 组合期权:水平价差
  • day29 消息队列
  • CST支持对哪些模型进行特征模仿真?分别有哪些用于特征模分析的求解器?
  • 信号处理函数中调用printf时,遇到中断为什么容易导致缓冲区损坏?
  • 介绍一下线程的生命周期及状态?
  • 化工设备健康管理解决方案:基于多物理场监测的智能化技术实现
  • 【系统分析师】软件需求工程——第11章学习笔记(上)
  • 堆(Java实现)
  • 大数据架构演变之路
  • [激光原理与应用-222]:机械 - 3D设计与2D设计的异同比较
  • 赋值运算符指南
  • GoBy 工具安装 | Windows 操作系统安装 GoBy
  • 某市智慧社区企业管理平台原型设计:数据驱动的社区治理新路径
  • 常用hook钩子函数