资讯动态

PostgreSQL 服务端机制与 SQL 实战深度解析:从 MVCC 到查询优化器

发布时间:2026/10/14 9:06:19 来源:尧图企业网站定制
工业数采平台侧的关系型数据库终于有了系统篇——为什么 PostgreSQL 能扛住高并发写入却不怕锁死为什么你的 SQL 时快时慢VACUUM 到底在干什么本文一次性讲透。1. 背景1.1 为什么还需要一篇数据库博客之前已经写过 SQLite3嵌入式 OLTP、DuckDB嵌入式 OLAP、RocksDBLSM KV 引擎、TDengine时序数据库、Redis内存 KV、etcd分布式协调 KV——覆盖了嵌入式、时序、缓存、协调四类存储。但在真实工业数采平台里还有一类数据始终需要通用关系型数据库设备台账、产线/工位元数据、用户与权限、工艺参数版本、告警规则配置、报表模板业务侧订单/工单/IPQC 检验记录等结构化业务数据这些数据规模中等、关系复杂、需要强一致性事务与灵活查询时序库和 KV 都不合适。PostgreSQL 是这个领域的开源事实标准1986 年诞生于伯克利大学 POSTGRES 项目BSD 许可、社区驱动 30 年支撑了从个人项目到大型互联网公司的生产系统。它的设计哲学是功能全、正确性优先、可扩展完整 MVCC、多版本事务、WAL 崩溃恢复、丰富索引类型、JSONB、窗口函数、CTE、表分区、流复制/逻辑复制、PostGIS/pgvector 扩展……几乎每个特性都值得单独成篇。但正如本系列其他服务端篇Redis 源码、Kafka broker、etcd一样怎么用之外的内部为什么才是排障的关键为什么高并发写入时 SELECT 不会阻塞—— MVCC 多版本机制为什么跑了几年的表越来越大、查询越来越慢—— 膨胀与 autovacuum为什么 UPDATE 一条记录会复制一份数据—— 元组版本链为什么同样的 SQL 有时走索引有时全表扫—— 查询规划器与统计信息为什么 max_connections 飙高后整库变慢—— 进程模型与共享内存一句话定位本篇是一篇通用关系型数据库服务端机制篇与 TDengine 构成工业数采平台的关系库 时序库双库底座。1.3 适用场景工业数采平台的元数据、配置、业务表存储设备台账/点位配置/告警记录/工单需要 ACID 事务、复杂 JOIN、灵活查询的中等规模结构化数据需要流复制高可用 / 逻辑复制做数据分发的中型系统2. 核心概念速览2.1 总体架构进程模型不是线程模型┌─────────────────────────────────────┐ │ postmaster │ 主守护进程 │ (信号管理 / 子进程派生 / 崩溃重启) │ └──────────────┬──────────────────────┘ │ fork() ┌───────────────┼───────────────────────┐ │ │ │ ┌─────▼─────┐ ┌──────▼──────┐ ┌────────────▼──────────────┐ │ backend │ │ background │ │ 辅助进程组 │ │ (每个连接 │ │ writer │ │ walwriter / checkpointer │ │ 一个进程) │ │ autovacuum │ │ logical replication │ └───────────┘ └─────────────┘ └───────────────────────────┘ │ 共享内存shared memory │ buffer pool / WAL buffers / lock table / catalog cache每连接一进程fork 自 postmaster不是线程模型连接越多进程越多内存消耗线性增长共享内存中shared_buffers数据页缓冲池、WAL buffer、锁表、统计信息、系统目录缓存崩溃时 postmaster 负责重启 backend不需要人工干预相比 MySQL 更自治。2.2 MVCC多版本并发控制MVCC 是 PostgreSQL 并发模型的核心也是读写不互斥的物理基础每个数据行tuple头携带xmin / xmax创建它的事务 ID、删除/更新它的事务 IDUPDATE 不是就地覆盖而是插入新版本 在旧版本上标记 xmax形成版本链t_ctid 指向下一个版本每个事务开始时会获取一个快照当前活跃事务列表 snapshot据此判断哪些版本可见读不阻塞写、写不阻塞读SELECT 永远看到自己快照下的一致视图即使其他事务正在修改同一行。2.3 事务隔离级别标准四档隔离级别脏读不可重复读幻读说明READ UNCOMMITTED可能PG 不实现等价 RC可能可能PG 中与 RC 相同READ COMMITTED默认不可能可能可能每条语句取新快照同一事务内两次 SELECT 可能结果不同REPEATABLE READ不可能不可能可能PG 的 SSI 可防部分事务内所有语句用同一快照PG 实现为快照隔离SERIALIZABLE不可能不可能不可能PG 用 SSI可串行化快照隔离检测冲突并报错关键点PG 的 REPEATABLE READ 是快照隔离比很多数据库如 MySQL InnoDB 默认 RR 的 next-key lock实现更干净——无间隙锁、无幻读锁等待冲突靠提交时检测而非加锁阻塞。2.4 WALWrite-Ahead Log与崩溃恢复所有修改先写 WAL预写日志默认 16MB 一段pg_wal/ 目录再写数据页数据页由background writer / checkpointer异步刷盘checkpoint 时推进 pg_control 中的恢复点崩溃恢复 从最近 checkpoint 重放 WAL 直到日志末尾REDO因此掉电不丢已提交事务未提交事务自然回滚用 WAL 中的 CLR 或 undo 链。2.5 锁机制表锁与行锁表锁8 种粒度ACCESS SHARE → ROW SHARE → ROW EXCLUSIVE → SHARE UPDATE EXCLUSIVE → SHARE → SHARE ROW EXCLUSIVE → EXCLUSIVE → ACCESS EXCLUSIVEDDL 与 DML 之间互相排斥关系由锁强度矩阵决定行锁MVCC 下 UPDATE/DELETE 通过修改行的 xmax 事务状态判断谁在锁SELECT FOR UPDATE 显式加锁行锁信息存在元组头 事务状态里不需要独立锁记录表这是与 InnoDB 的最大差异之一死锁检测后台 deadlock_timeout默认 1s触发检测检测到即回滚一方事务。2.6 查询执行流水线SQL 文本 → 词法/语法解析parser 生成 parse tree → 分析/重写analyzer rule rewriter视图在此展开 → 规划planner生成多种候选执行计划并估算代价 → 执行executor按计划树执行返回结果规划器依据统计信息pg_statistic由 ANALYZE 收集估算每个算子的代价顺序扫描、索引扫描、嵌套循环、哈希连接、排序等EXPLAIN (ANALYZE, BUFFERS) 可以看到真实执行计划与行数估算偏差——估算偏差大是性能问题的头号来源。2.7 膨胀与 VACUUM因为 UPDATE 是插新版本旧版本不能立即删除——可能有旧快照仍在读取可回收的旧版本由VACUUM清理autovacuum 守护进程按阈值自动触发清理不及时 → 表膨胀dead tuple 堆积→ 顺序扫描变慢、索引变大VACUUM FULL 可物理收缩但锁表、重写文件普通 VACUUM 不锁表。2.8 复制流复制与逻辑复制流复制物理复制WAL 实时传输到 standbystandby 重放支持同步/异步、级联、pg_rewind 回退主从自动/手动切换逻辑复制逻辑解码发布/订阅模型可选择性复制表/行/列可用于数据分发、迁移、异构同步如到 Kafka 用 pgoutput 插件解码 WAL。3. API 说明与速查3.1 SQL 高频语法速查PostgreSQL 特色-- DDL建表含约束、默认值、注释 CREATE TABLE device ( id BIGSERIAL PRIMARY KEY, -- 自增主键 code VARCHAR(32) NOT NULL UNIQUE, -- 设备编码 line_id INTEGER REFERENCES line(id), -- 外键 status SMALLINT NOT NULL DEFAULT 0, -- 状态 meta JSONB DEFAULT {}::jsonb, -- 灵活扩展字段 created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX idx_device_status ON device(status); -- 普通索引 CREATE INDEX idx_device_meta ON device USING gin (meta); -- JSONB GIN 索引 CREATE INDEX idx_device_line_status ON device(line_id, status); -- 复合索引 -- DMLUPSERTON CONFLICT 是 PG 大杀器 INSERT INTO device(code, line_id, status) VALUES (CNC-001, 1, 1) ON CONFLICT (code) DO UPDATE SET status EXCLUDED.status, meta EXCLUDED.meta; -- CTEWITH 递归工艺 BOM 树/组织树 WITH RECURSIVE sub AS ( SELECT id, parent_id FROM process_tree WHERE id 100 UNION ALL SELECT t.id, t.parent_id FROM process_tree t JOIN sub s ON t.parent_id s.id ) SELECT * FROM sub; -- 窗口函数设备按产线排名/滚动平均 SELECT code, line_id, load, ROW_NUMBER() OVER (PARTITION BY line_id ORDER BY load DESC) AS rn, AVG(load) OVER (PARTITION BY code ORDER BY created_at ROWS BETWEEN 4 PRECEDING AND CURRENT ROW) AS avg5 FROM device_metrics; -- 分区表按时间分区声明式分区 CREATE TABLE alarm_log ( id BIGSERIAL, device_id INT, msg TEXT, occurred_at TIMESTAMPTZ ) PARTITION BY RANGE (occurred_at); CREATE TABLE alarm_log_2026_10 PARTITION OF alarm_log FOR VALUES FROM (2026-10-01) TO (2026-11-01);3.2 psql 常用命令命令作用\l / \dt / \d device列库/表/表结构\di / \dx索引 / 扩展\timing显示语句耗时\x行转列显示\copy device TO device.csv CSV HEADER客户端导出服务器端用 COPY\password改密码SHOW shared_buffers;看配置3.3 EXPLAIN 输出解读EXPLAIN (ANALYZE, BUFFERS, COSTS OFF) SELECT * FROM device WHERE status 1 AND line_id 2; QUERY PLAN ----------------------------------------------------------------------------- Index Scan using idx_device_line_status on device (actual time0.021..0.043 rows12 loops1) Index Cond: (line_id 2) Filter: (status 1) -- 索引未完全覆盖条件的过滤 Buffers: shared hit5 read0 -- 全部命中共享缓冲 Planning Time: 0.2 ms Execution Time: 0.05 ms读计划三要素节点类型Seq Scan/Index Scan/Index Only Scan/Nested Loop/Hash Join/Hash Aggregate...、rows 估算 vs actual偏差大 → 统计信息过期或谓词不可估、Buffers 命中情况read0 说明都在内存。3.4 备份与恢复# 逻辑备份跨版本迁移常用 pg_dump -h host -U user -d mydb -Fc -f mydb.dump pg_restore -h host -U user -d newdb mydb.dump # 物理备份一致快照需配合 WAL 归档 pg_basebackup -h host -U repluser -D /backup/base -X stream3.5 编程接口速查Go推荐 pgx 或 database/sql pgx 驱动import ( context github.com/jackc/pgx/v5/pgxpool ) func main() { ctx : context.Background() pool, err : pgxpool.New(ctx, postgres://user:passlocalhost:5432/mydb?pool_max_conns20) if err ! nil { panic(err) } defer pool.Close() // 查询多行 rows, _ : pool.Query(ctx, SELECT code, status FROM device WHERE line_id$1, 2) defer rows.Close() for rows.Next() { var code string; var status int16 rows.Scan(code, status) } // 批量插入copy 协议最快 _, err pool.CopyFrom(ctx, pgx.Identifier{device}, []string{code, line_id, status}, pgx.CopyFromRows([][]any{{CNC-001, 1, 1}, {CNC-002, 1, 0}})) }Pythonpsycopg3import psycopg from psycopg.rows import dict_row with psycopg.connect(hostlocalhost dbnamemydb useruser passwordpass, row_factorydict_row) as conn: # 自动提交模式 conn.autocommit True with conn.cursor() as cur: cur.execute(SELECT code, status FROM device WHERE line_id %s, (2,)) for row in cur.fetchall(): print(row) # 批量执行 cur.executemany( INSERT INTO device(code, line_id, status) VALUES (%s, %s, %s) ON CONFLICT (code) DO UPDATE SET status EXCLUDED.status, [(CNC-001, 1, 1), (CNC-002, 1, 0)])4. 详细使用可运行示例4.1 Docker 快速部署docker run -d --name pg16 \ -e POSTGRES_USERadmin -e POSTGRES_PASSWORDsecret -e POSTGRES_DBindustry \ -p 5432:5432 \ -v pgdata:/var/lib/postgresql/data \ postgres:16 psql postgres://admin:secretlocalhost:5432/industry生产建议数据目录挂宿主机磁盘并监控 IO开启 pg_stat_statements 扩展默认自带但需创建。4.2 事务隔离级别演示同一张表看差异-- 会话 A BEGIN ISOLATION LEVEL READ COMMITTED; SELECT count(*) FROM device; -- 假设 100 行 -- 会话 B另开一个 psql BEGIN; UPDATE device SET status 9 WHERE id 1; -- 未提交 -- 会话 A 再查RC看不到 B 未提交修改 SELECT count(*) FROM device; -- 仍 100 行不阻塞 SELECT * FROM device WHERE id 1; -- 仍旧值读不阻塞 -- 会话 B COMMIT; -- 会话 A 同一事务内再查RC 取新快照 → 看到新值RR 则仍是旧值这是工业数采场景排查读到旧数据的经典现场RC 下长事务内多次查询可能读到不同快照需要时改用 REPEATABLE READ。4.3 EXPLAIN 实战找出慢 SQL-- 先确保统计信息新鲜 ANALYZE device; -- 比较三种写法 EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM device WHERE status 1; -- 可能 Seq Scan EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM device WHERE status 1 AND line_id 2; -- 复合索引 -- 检查估算偏差 EXPLAIN SELECT * FROM device WHERE created_at now() - interval 1 hour; -- 若 rows 估算远小于 actual说明统计信息过期 → ANALYZE / 提高 default_statistics_target4.4 流复制主从搭建3 条命令级# 主库postgresql.conf wal_level replica max_wal_senders 5 # pg_hba.conf 增加host replication repluser 192.168.1.0/24 md5 # 从库物理备份 配置 recovery pg_basebackup -h 主库IP -U repluser -D /var/lib/postgresql/data -X stream -R # -R 自动生成 standby.signal 与 primary_conninfo启动从库即可追主4.5 逻辑复制发布/订阅跨库/异构分发-- 发布端 CREATE PUBLICATION pub_device FOR TABLE device, device_metrics; -- 订阅端 CREATE SUBSCRIPTION sub_industry CONNECTION host主库IP dbnameindustry useradmin passwordsecret PUBLICATION pub_device;工业数采场景把关系库中的设备配置变更逻辑复制到采集网关侧缓存/或下游 Kafka 桥实现配置热同步。4.6 工业数采双库落地PostgreSQL TDengine 分工数据存储说明设备台账/点位配置/告警规则/用户权限PostgreSQL关系建模、事务更新、JOIN 查询点位时序数据温度/负载/良率TDengine高吞吐追加写、降采样、保留策略实时最新值/命令队列/分布式锁Redis低延迟缓存采集消息缓冲Kafka削峰、解耦、可回溯典型链路设备 → 采集网关 → Kafka → TDengine(时序) 消费侧同步元数据到 PostgreSQLWeb/API 层用 PostgreSQL 提供设备树、告警记录、报表TDengine 提供趋势曲线。5. 底层实现剖析5.1 元组Tuple与版本链堆文件中的行布局简化[ PageHeader (24B) ] [ ItemId 数组 ] [ tuple 数据区 ] HeapTupleHeader: t_xmin : 插入此版本的事务 ID t_xmax : 删除/更新此版本的事务 ID0 表示有效 t_cid : 命令 ID同事务内区分命令 t_ctid : 指向下一个版本自身 最新版本 t_infomask: 位标志含 xmin/xmax 是否已提交的 hint bit可见性判断t_xmin 在快照活跃列表中 → 不可见t_xmax 已提交且非本事务 → 该版本被删除沿 t_ctid 链向下找最新可见版本hint bitHEAP_XMIN_COMMITTED 等由首次访问写入避免每次查事务提交状态commit log长事务/长连接会阻止 old version 清理autovacuum 只清理所有活跃快照都不可见的版本。5.2 WAL 记录与 Checkpoint每条修改产生 WAL record含 XLOG 记录头lsn、事务、资源管理器类型 数据关键 LSN 概念redo最近 checkpoint 的 WAL 位置、flush、write、insertsynchronous_commit on 时事务提交必须等 WAL flush 到磁盘才返回成功这就是提交不丢的保证checkpoint 由 checkpoint_timeout默认 5min或 max_wal_size默认 1GB触发checkpoint 后旧 WAL 可回收wal_levelminimal不可做 PITR/复制/ replica流复制/ logical逻辑复制。5.3 查询规划器代价模型每个算子有启动代价 每行代价估算公式与 seq_page_cost1、random_page_cost4、cpu_tuple_cost0.01 等参数相关索引选择依据选择性pg_stats 中 n_distinct/most_common_vals/histogram_boundsJOIN 三策略Nested Loop小表驱动无索引时 O(N×M)、Hash Join等值连接、无索引可用、Merge Join已排序输入random_page_cost 调低如 SSD 设 1.1会更倾向走索引统计信息过期 → 计划失真 → 需要 ANALYZE/VACUUM ANALYZE。5.4 索引B-tree 与 GIN 一瞥B-tree默认多路平衡树页内键值有序支持 BETWEEN LIKE 前缀%复合索引最左前缀原则GIN倒排JSONB/全文检索/数组用jsonb_path_ops 更快但功能少、jsonb_ops 支持 ? ?| ? 运算符插入时先入 pending listgin_pending_list_limit 满后批量合并GiST/SP-GiST空间/范围数据BRIN按物理块区间存 min/max适合时间戳类大表分区表 BRIN 是时序类查询利器覆盖索引/Index Only Scan(line_id, status) 包含所需列时无需回表需要 visibility map 支持。5.5 autovacuum 工作逻辑后台进程周期autovacuum_naptime1min扫描各表比对 pg_stat_user_tables 中 dead tuple 数与阈值autovacuum_vacuum_threshold50 autovacuum_vacuum_scale_factor0.2 的百分比触发后对目标表执行 VACUUM ANALYZEautovacuum_analyze_* 同套阈值大表可单独配置ALTER TABLE device SET (autovacuum_vacuum_scale_factor 0.05, autovacuum_vacuum_threshold 1000);禁止全局关闭 autovacuum——那是生产事故的常见源头。6. 常错点/坑25 条隔离级别误解RC 下同一事务多次 SELECT 结果可能不同长事务内重复读取需 RR误以为事务内一定一致是排障翻车第一原因。长事务/长连接不释放一个未提交的长事务会阻止 autovacuum 清理它的旧版本 → 表膨胀连接池要设置 idle_in_transaction_session_timeout。UPDATE 造成的膨胀被忽略高频 UPDATE 点位状态表而不 VACUUM表无限膨胀低基数字段频繁更新应评估状态放 Redis 低频落库。VACUUM FULL 当普通维护VACUUM FULL 需要 ACCESS EXCLUSIVE 锁阻塞读写大表会停服日常用普通 VACUUM/autovacuum。N1 查询循环里逐行查外键 → 千行变千次查询应 JOIN 或 IN (...) 批量。统计信息过期导致计划劣化大批量写入/删除后不 ANALYZE规划器选错计划autovacuum 会顺手做 ANALYZE别关。复合索引列顺序错(line_id, status) 不能直接服务于 WHERE status1最左前缀原则。索引列上套函数WHERE date(created_at) 2026-10-13 无法走普通索引改范围条件 created_at ... AND created_at ... 或建表达式索引。random_page_cost 未按磁盘调机械盘默认 4 合理SSD 应降1.1~1.5否则规划器过度回避索引。shared_buffers 乱调设得太大 内存 1/3反而引发频繁 evict 与内核双缓冲常规 25% 左右 交给 OS page cache 兜底。max_connections 开太高每连接一个 backend 进程内存随连接数线性增长用连接池pgbouncer/pgxpool而不是狂开连接。ON CONFLICT 依赖唯一约束没有唯一索引/唯一约束时 ON CONFLICT 直接报错先建 UNIQUE。JSONB 当万能字段滥用无索引 JSONB 查询走全表扫高频过滤字段应提取为普通列建索引。时区与 TIMESTAMP 混用TIMESTAMP WITHOUT TIME ZONE 存本地时间易错乱统一 TIMESTAMPTZ 存储、展示时转时区。text vs varchar(n)PG 中两者性能几乎无差text 无长度上限更省心char(n) 有 padding 坑。误以为 DELETE 立即释放空间普通 DELETE 只是标记 dead tuple空间要 VACUUM 才回收大清理用 TRUNCATE 或分批 VACUUM。备份只做逻辑不做 WAL 归档pg_dump 只能还原到备份点要时间点恢复PITR必须 wal_levelreplica 归档 定期 pg_basebackup。主从切换手工操作生疏流复制故障恢复需要 pg_ctl promote/pg_rewind生产应演练切换流程。CHECKPOINT 手工执行被当作优化手工 checkpoint 只是把脏页提前刷盘不能提升性能反而造成 IO 尖峰。seq_scan 出现在应该走索引的查询先看估算偏差、再看 enable_seqscan 是否被关闭、再看统计信息。LIMIT/OFFSET 深分页慢OFFSET 1000000 仍扫描前面所有行用 (id, created_at) 游标式分页keyset pagination。COUNT(*) 大表慢PG 无常量维护的行数需 EXPLAIN 看是否走 index-only真高频计数用物化视图/触发器计数表。连接字符串密码明文/权限过大pg_hba.conf 别开 trust最小权限账号pgpass 或环境变量管理凭据。逻辑复制忘记 wal_levellogical逻辑复制需要 logical 级别 WAL且主库重启后复制槽继续推进pg_replication_slots 要监控防 WAL 撑爆磁盘。default_statistics_target 太低大表/多值分布字段估算差可针对列 ALTER TABLE ... ALTER COLUMN ... SET STATISTICS 1000。7. 性能优化清单10 条连接池化应用侧 pgxpool/GORM 连接池 必要时刻 pgbouncer连接数控制在 20~100 量级。索引精修只建查询真正用的索引每多一个索引多一份写放大复合索引按等值在前、范围在后排。表分区大日志表按时间范围分区配合 BRIN 索引分区裁剪避免跨区扫描。统计信息新鲜大量 DML 后触发 ANALYZE大表调 autovacuum_* 参数。写放大治理低频更新的配置表放心走关系模型高频点位状态走 Redis/TDengine避免 UPDATE 风暴。批量 DMLCOPY / CopyFrom / 多值 INSERT 比逐行插入快一个数量级。WAL 与磁盘WAL 放独立 SSD 或 IOPS 高的盘synchronous_commitoff 只用于可容忍亚秒丢失的批处理会话。查询重写用 CTE 避免多次扫同一表EXISTS 替代 IN 大子查询FILTER 子句做多条件聚合。只读副本分流报表/大查询走 standby流复制只读副本主库专注写入。监控闭环pg_stat_statements pg_stat_activity 抓慢 SQL 与长事务 Prometheus postgres_exporter 告警连接数/膨胀率/复制延迟。8. 工业数采落地建议关系库承担平台侧业务数据与 TDengine时序数据面、Redis实时面、Kafka消息面形成完整数据底座设备树与配置line → device → point 三表关系建模点位配置 JSONB 存扩展属性配置变更走 ON CONFLICT UPSERT告警记录按月分区大表 (device_id, occurred_at) 复合索引报表按窗口函数聚合IPQC/工单事务保证检验记录 判定结果 设备状态一致性更新配置热同步逻辑复制把设备配置变更同步到边缘网关侧缓存连接规范Go 侧 pgxpool idle_in_transaction_session_timeout 指标接入 Prometheus。9. 总结五要点模型进程模型 共享内存每连接一 backendMVCC 让读写互不阻塞这是并发能力的根。正确性WAL 预写日志保证崩溃不丢已提交事务四档隔离级别中 PG 用快照隔离实现 RR/SERIALIZABLE。性能真相SQL 快慢由规划器基于统计信息决定EXPLAIN 统计信息新鲜 索引匹配是调优三板斧。运维底线别关 autovacuum、别让长事务悬挂、备份必须配 WAL 归档、连接用池化。生态定位与 TDengine 构成工业数采平台关系库 时序库双底座与 Redis/Kafka 组成完整数据链路。10. FAQ10 条速查PG 和 MySQL 怎么选PG 功能全索引/JSONB/CTE/分区/逻辑复制、更重正确性MySQL 生态成熟、运维资料多、分库分表工具链丰富。团队熟悉度 功能需求是决定性因素。为什么 SELECT 和 UPDATE 互不阻塞MVCCUPDATE 生成新版本SELECT 读自己快照下的旧版本物理上互不干扰。表膨胀了怎么办先查 pg_stat_user_tables.n_dead_tup 确认等 autovacuum 或手动 VACUUM物理收缩才用 VACUUM FULL需停写窗口。查询一会儿快一会儿慢大概率是统计信息/缓存状态/连接池波动用 EXPLAIN (ANALYZE, BUFFERS) 对比、看 pg_stat_statements 平均耗时。怎么快速定位慢 SQLpg_stat_statements 按 total_time 倒序pg_stat_activity 查当前执行与等待事件。连接数够吗看 pg_stat_activity 的 active/idle 分布与 max_connections优先连接池而不是调大 max_connections。主从同步落后怎么查pg_stat_replication 的 write_lag/flush_lag/replay_lag同步复制时还需 synchronous_standby_names 配置。能不能把时序数据也放 PG可以分区 BRIN但海量高频写入的吞吐/保留策略/降采样不如专用时序库工业数采建议按双库分工。JSONB 和普通列哪个好扩展性强、schema 灵活用 JSONB配 GIN高频查询/约束/外键字段用普通列。备份策略最低要求wal_levelreplica 每日 pg_basebackup 连续 WAL 归档archive_modeon可支持任意时间点恢复至少每周验证一次恢复演练。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑