# PostgreSQL 教程与生产实践指南 Canonical URL: https://pg.edu.rich/docs Last reviewed: 2026-08-02 这不是 PostgreSQL 官方手册的替代品,而是一张更容易进入官方手册的地图。内容以 **PostgreSQL 18** 为当前基线,同时避免在没有说明时依赖单一版本的特性。 ## 两种阅读模式 [#两种阅读模式] ### 人类学习模式 [#人类学习模式] 按顺序读 [从这里开始](/docs/start-here)。每篇包含:你会完成什么、最小示例、为什么如此、如何验证、下一步是什么。第一次阅读时不要求记住系统目录和所有 SQL 语法。 ### AI 检索模式 [#ai-检索模式] 从 [AI / Agent 入口](/docs/ai) 进入。页面使用稳定标题、显式前置条件、可复制 SQL、边界条件和失败模式。让 Agent 优先检索相关小节,不要一次塞入整站内容。 ## 文档约定 [#文档约定] | 标记 | 含义 | | ------ | ------------------------- | | **默认** | PostgreSQL 默认行为;仍应在目标实例验证 | | **建议** | 适用于大多数新项目,不代表唯一正确答案 | | **危险** | 可能锁表、丢数据、泄露权限或制造长事务 | | **验证** | 执行后用于确认结果的命令或查询 | 事实性细节以 [PostgreSQL 18 官方文档](https://www.postgresql.org/docs/18/) 为准。本站的价值是路径、示例、约束和跨章节连接。 --- # PostgreSQL 19:新功能、发布时间与 18 升级 19 指南 Canonical URL: https://pg.edu.rich/docs/postgresql-19 Last reviewed: 2026-08-02 截至 **2026-08-02**,PostgreSQL 19 的最新公开测试版是 **Beta 2**,还不是正式生产版本。PostgreSQL 官方路线图计划在 **2026 年 9 月**发布 19;Beta 2 公告使用了更保守的 **2026 年 9–10 月**窗口。最终日期、功能细节和兼容性要求仍可能变化。 官方鼓励用真实工作负载测试 Beta,但明确不建议运行在生产环境。本页适合提前评估、建立兼容矩阵和演练 PostgreSQL 18 升级 19;正式切换应等待 GA、目标 minor、扩展和托管平台支持。 ## PostgreSQL 19 最新消息与发布时间 [#postgresql-19-最新消息与发布时间] | 日期 | 官方进展 | 对使用者的意义 | | ----------- | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | | 2026-06-04 | [PostgreSQL 19 Beta 1 发布](https://www.postgresql.org/about/news/postgresql-19-beta-1-released-3313/) | 功能预览开放,适合开始 CI 与应用兼容测试 | | 2026-07-16 | [PostgreSQL 19 Beta 2 发布](https://www.postgresql.org/about/news/postgresql-19-beta-2-released-3350/) | 修复 Beta 1 回归,并继续调整 temporal、SQL/PGQ、逻辑解码和 autovacuum 等实现 | | 2026-09(计划) | [官方路线图的目标月份](https://www.postgresql.org/developer/roadmap/) | 不是不可变承诺;Beta 公告保留 9–10 月发布窗口 | Beta 2 仍允许数据库行为、API 和功能细节发生小幅变化。跟踪时以 [PostgreSQL 19 Release Notes](https://www.postgresql.org/docs/19/release-19.html) 和官方新闻为准,不以第三方功能清单作为上线依据。 ## PostgreSQL 19 Linux 软件包可用性 [#postgresql-19-linux-软件包可用性] ### 发行版官方仓库:postgresql-19 PkgSeek 软件包快照;核对时间:2026-08-02 15:47:58 UTC。 > 没有准确索引坐标。这表示当前快照未收录,不等于软件包不存在。 来源:[PkgSeek 软件包查询](https://pkgseek.com/search?q=postgresql-19)。发行版 revision 和回溯补丁属于完整版本身份。 ### PGDG 仓库:postgresql-19 PkgSeek 软件包快照;核对时间:2026-08-02 15:47:58 UTC。 > 没有准确索引坐标。这表示当前快照未收录,不等于软件包不存在。 来源:[PkgSeek 软件包查询](https://pkgseek.com/search?q=postgresql-19)。发行版 revision 和回溯补丁属于完整版本身份。 这两个快照用于追踪正式软件包落地情况,不是 PostgreSQL 19 的发布状态来源。Beta tarball、开发构建或容器存在,不代表发行版仓库已经提供可用于生产升级的 `postgresql-19`。进入 GA 后仍应等待目标操作系统、CPU 架构、扩展和备份工具形成完整兼容矩阵。 ## PostgreSQL 19 有哪些新功能 [#postgresql-19-有哪些新功能] 下面是截至本页核对日最值得工程团队测试的方向,不代表最终发布说明的完整摘要。 ### SQL、图查询与时间数据 [#sql图查询与时间数据] * **SQL/PGQ Property Graph Queries**:在关系数据上定义并查询 property graph;应验证驱动、SQL parser、ORM 和 AI SQL 生成器是否认识新语法。 * **`FOR PORTION OF`**:让 `UPDATE`、`DELETE` 针对时间范围操作,适合测试 temporal 数据模型,但 Beta 2 仍修复了多项相关问题。 * **`GROUP BY ALL`**:自动对 target list 中非 aggregate、非 window 项分组。 * **Window functions `IGNORE NULLS` / `RESPECT NULLS`**:适用于 `lead()`、`lag()`、`first_value()`、`last_value()` 和 `nth_value()`。 * **`INSERT ... ON CONFLICT DO SELECT ... RETURNING`**:可返回发生冲突的行,并选择性加锁。 ### 运维、性能与可观测性 [#运维性能与可观测性] * **`REPACK` 与 `REPACK CONCURRENTLY`**:统一 `VACUUM FULL` / `CLUSTER` 的重写能力,并提供降低排他锁影响的新路径;旧命令为兼容仍保留。 * **分区拆分与合并**:新增 `ALTER TABLE ... SPLIT/MERGE PARTITIONS`。 * **并行 autovacuum worker**,以及 `pg_stat_autovacuum_scores`、`pg_stat_lock`、`pg_stat_recovery` 等观测视图。 * 异步 I/O read-ahead、`COPY FROM` SIMD、radix sort、外键检查等性能改进。 * `EXPLAIN ANALYZE` 新增 `IO` 选项;`EXPLAIN (ANALYZE, WAL)` 可报告 full-page write bytes。 * 新数据默认 TOAST 压缩从 `pglz` 改为 `lz4`。 PostgreSQL 19 的 `REPACK (CONCURRENTLY)` 是基于 logical decoding 的核心 SQL command,对 replica identity、unlogged/partitioned/system table、replication slot 和额外磁盘有约束;第三方 `pg_repack` 是独立 extension 与 CLI。两者不能共享未经验证的运行手册。参见 [扩展生态选型](/docs/reference/extensions-ecosystem) 与 [PostgreSQL 19 REPACK 文档](https://www.postgresql.org/docs/19/sql-repack.html)。 如果 Agent 的目标实例还是 PostgreSQL 18,不要让它生成 SQL/PGQ、`FOR PORTION OF`、`GROUP BY ALL` 等 19 才有的语法。把 `server_version_num`、允许语法和扩展版本写进检索上下文或工具契约。 ## PostgreSQL 18 升级 19:需要注意什么 [#postgresql-18-升级-19需要注意什么] PostgreSQL 18 → 19 是 **major upgrade**,不能把 18 的 data directory 直接交给 19 启动。可选路径是 `pg_upgrade`、逻辑 dump/restore 或逻辑复制。升级前优先处理以下兼容性变化。 ### 1. 认证与安全变化 [#1-认证与安全变化] * **RADIUS 支持被移除**;仍依赖 RADIUS 的环境必须先设计替代认证路径。 * PostgreSQL 18 已把 MD5 密码标记为 deprecated;19 会在 MD5 认证成功后发出 warning。迁移计划应推进 SCRAM,而不是只屏蔽 warning。 * 新增密码即将过期 warning,默认阈值为 7 天;检查监控是否会把预期 warning 当故障。 ### 2. SQL 与对象兼容性 [#2-sql-与对象兼容性] * `standard_conforming_strings` 在服务器端强制为 `on`。如果旧环境曾设为 `off`,使用 19 版 `pg_dump` / `pg_dumpall` 重新导出,或先修正设置与应用转义行为。 * database、role、tablespace 名称不能包含 CR/LF;`pg_upgrade` 会拒绝此类 cluster。 * 使用 `btree_gist` 的 `inet` / `cidr` index 会阻塞 `pg_upgrade`,因为旧 opclass 可能漏行;让 `pg_upgrade --check` 给出实际阻塞项,再按 release notes 处理。 * `MULE_INTERNAL` encoding 被移除,相关数据库必须以其他 encoding dump/restore。 ### 3. 默认值、性能与监控变化 [#3-默认值性能与监控变化] * **JIT 默认关闭**。大型分析查询不能假设升级后计划行为不变;分别在 `jit=off/on` 下记录执行时间和计划。 * `max_locks_per_transaction` 默认值从 64 变为 128,同时锁内存计算发生变化;不要只复制旧配置数字,应重新做容量评估。 * `pg_stat_subscription_stats.sync_error_count` 更名为 `sync_table_error_count`;等待事件类型 `BUFFERPIN` 更名为 `BUFFER`。修正 dashboard、告警和采集 SQL。 * 新默认只影响新写入数据,不代表升级后所有旧 TOAST 值会自动改用 LZ4;不要把默认变化等同于无条件压缩收益。 ### 4. 扩展、驱动与平台 [#4-扩展驱动与平台] `pg_upgrade` 可以检查核心 cluster 的许多二进制条件,但不能证明第三方 module 与 PostgreSQL 19 二进制兼容。为 PostGIS、pgvector、TimescaleDB、自定义 C extension、审计插件、备份代理、pooler、ORM 和驱动分别记录: | 组件 | 需要确认 | | --------- | ---------------------------------------------------------- | | Extension | 19 对应 package/shared library、支持声明、升级脚本、index 重建要求 | | 驱动与 ORM | server version detection、19 新/变更语法、prepared statement、类型映射 | | 连接池 | startup parameter、认证、failover 与连接回收行为 | | 备份与 CDC | 新版本 catalog、WAL/逻辑解码、restore 演练 | | 云数据库 | 区域、SKU、扩展版本、升级窗口与回退能力;以服务商上线公告为准 | ## PostgreSQL 18 升级 19 实战清单 [#postgresql-18-升级-19-实战清单] ### 阶段 A:现在就可以做 [#阶段-a现在就可以做] 1. 固定一份 PostgreSQL 18 生产备份并完成 restore 验证。 2. 清点 extension、collation、replication slot、tablespace、自定义 full-text 文件、认证方式和外部 module。 3. 用 PostgreSQL 19 Beta 2 建立**可丢弃**的测试环境,运行 migration、应用测试、备份恢复、CDC 和关键查询 benchmark。 4. 对比 `EXPLAIN (ANALYZE, BUFFERS, WAL)`;单独评估 JIT 默认变化与新 I/O 行为。 5. 在 CI 中禁止把 PostgreSQL 19 专属语法下发给 18 实例。 把 PostgreSQL 18.4 设为阻断发布的生产门禁,把 PostgreSQL 19 Beta 2 设为前瞻兼容通道;后者可以先允许失败,但每个失败都应归类并在 GA 采用前清零。完整流水线见 [PostgreSQL 安全迁移与零停机 Schema 变更](/docs/operations/safe-migrations)。 ### 阶段 B:正式切换前 [#阶段-b正式切换前] 先运行 **19 版** `pg_upgrade` 的只检查模式;路径必须替换为目标环境实际目录: ```bash /opt/postgresql/19/bin/pg_upgrade \ --old-bindir=/opt/postgresql/18/bin \ --new-bindir=/opt/postgresql/19/bin \ --old-datadir=/data/postgresql/18 \ --new-datadir=/data/postgresql/19 \ --check ``` `--check` 不迁移数据,但应使用与正式切换相同的 binary、extension、initdb 参数和 transfer mode 做演练。不要把示例路径直接复制到生产。 然后完成: * 锁定 PostgreSQL 19 正式 minor、OS package、container digest 与 extension 版本; * 根据数据量选择 `pg_upgrade` copy/clone/link/swap、dump/restore 或逻辑复制; * 记录预计停机、额外磁盘、统计恢复时间、DNS/连接池收敛时间; * 定义 rollback 判据、负责人和最晚回退时点; * 验证 standby、slot、sequence、large object、权限、RLS、job scheduler 和备份链路。 ### 阶段 C:切换后 [#阶段-c切换后] 1. 执行 `pg_upgrade` 生成的 post-upgrade / rebuild 脚本,完成前不要访问被标记的表。 2. 按工具提示补齐 optimizer statistics;再比较高流量查询的计划与延迟。 3. 检查错误率、认证 warning、复制 lag、WAL、autovacuum、锁和备份。 4. 进行一次从 PostgreSQL 19 新备份恢复的演练。 5. 只有通过业务验收且回退窗口关闭后,才清理 PostgreSQL 18 cluster。 完整步骤见 [PostgreSQL 19 pg\_upgrade](https://www.postgresql.org/docs/19/pgupgrade.html);复制与切换原则见 [复制、故障切换与升级](/docs/operations/replication-upgrades)。 ## PostgreSQL 19 常见问题 [#postgresql-19-常见问题] ### PostgreSQL 19 正式版发布了吗? [#postgresql-19-正式版发布了吗] 没有。截至 2026-08-02 最新版本是 Beta 2。官方路线图目标是 2026 年 9 月,Beta 公告给出的窗口是 9–10 月;最终以 PostgreSQL 官方新闻为准。 ### PostgreSQL 18 能直接升级到 PostgreSQL 19 吗? [#postgresql-18-能直接升级到-postgresql-19-吗] 可以按 major upgrade 路径直接迁移,不要求先经过其他 major。常见方法是 `pg_upgrade`、dump/restore 或逻辑复制;Beta 只用于演练,生产升级应等待正式版和依赖支持。 ### PostgreSQL 18 升级 19 会停机多久? [#postgresql-18-升级-19-会停机多久] 没有通用数字。停机由数据量、relation 数量、transfer mode、extension/reindex、统计恢复、连接切换和验证决定。必须在恢复出的真实数据副本上演练并测量。 ### 云 PostgreSQL 什么时候支持 19? [#云-postgresql-什么时候支持-19] 不同厂商、区域和 SKU 的节奏不同。不要从社区 GA 日期推导云平台可用日期;跟踪服务商官方版本矩阵,并核对 extension、PITR、read replica 和回退限制。参见 [云 PostgreSQL 选型](/docs/cloud/service-map)。 ### 现在应该从 PostgreSQL 18 升级 19 吗? [#现在应该从-postgresql-18-升级-19-吗] 现在适合建立测试矩阵,不适合把 Beta 作为生产默认。正式版发布后,也应先等待自己依赖的扩展、驱动、工具和托管平台给出明确支持,再根据业务收益与风险排期。 ## 事实状态与复核 [#事实状态与复核] 本页状态快照:**PostgreSQL 19 Beta 2,核对日期 2026-08-02**。进入 RC、GA 或 release notes 发生重要兼容性变化时,应更新标题说明、新闻时间线、升级阻塞项和 `updatedAt`。 --- # 5 分钟快速开始 Canonical URL: https://pg.edu.rich/docs/quickstart Last reviewed: 2026-08-02 下面的实例仅用于本地学习。密码写在命令行、端口暴露到宿主机都不是生产配置。 ### 启动实例 [#启动实例] ```bash docker run --name pg-guide \ -e POSTGRES_PASSWORD=dev-only-password \ -e POSTGRES_DB=playground \ -p 5432:5432 \ -v pg-guide-data:/var/lib/postgresql/data \ -d postgres:18 ``` ### 等待并检查 [#等待并检查] ```bash docker exec pg-guide pg_isready -U postgres -d playground docker logs pg-guide --tail 20 ``` 看到 `accepting connections` 再继续。 ### 打开 psql [#打开-psql] ```bash docker exec -it pg-guide psql -U postgres -d playground ``` ```sql CREATE TABLE notes ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, body text NOT NULL CHECK (length(body) > 0), created_at timestamptz NOT NULL DEFAULT now() ); INSERT INTO notes (body) VALUES ('hello, PostgreSQL'); SELECT id, body, created_at FROM notes; ``` ### 验证持久化 [#验证持久化] ```bash docker restart pg-guide docker exec pg-guide psql -U postgres -d playground \ -c "SELECT id, body, created_at FROM notes;" ``` 重启后仍能看到数据,说明命名卷已生效。 ## 连接字符串 [#连接字符串] 宿主机应用使用: ```text postgresql://postgres:dev-only-password@127.0.0.1:5432/playground ``` 不要把真实密码提交到 Git。生产环境使用 secret manager、最小权限应用角色和 TLS。 ## 清理 [#清理] ```bash docker rm -f pg-guide docker volume rm pg-guide-data ``` 第二条命令会永久删除练习数据;只在你确认不再需要时执行。 继续 [从这里开始](/docs/start-here),或者直接学习 [数据建模](/docs/core/data-modeling)。 --- # 从这里开始 Canonical URL: https://pg.edu.rich/docs/start-here Last reviewed: 2026-08-02 完成这条路线后,你应该能启动实例、用 `psql` 连接、设计一张有约束的表、在事务里修改数据,并用 `EXPLAIN` 判断查询是否走了预期路径。 ## 先记住五件事 [#先记住五件事] 1. **实例(cluster)里有多个 database**,database 里有 schema,schema 里有表、视图和函数。 2. 客户端连接的是一个具体 database;跨 database 查询不像跨 schema 查询那样直接。 3. 每条语句都在事务中运行。未显式 `BEGIN` 时,客户端通常为单条语句自动提交。 4. 约束是数据模型的一部分,不只是应用层校验的备份。 5. 索引有写入与维护成本;创建前后都要看真实执行计划。 ## 90 分钟路线 [#90-分钟路线] ### 0–10 分钟:运行并连接 [#010-分钟运行并连接] 完成 [快速开始](/docs/quickstart),保留一个名为 `pg-guide` 的本地容器。 ### 10–30 分钟:建立模型 [#1030-分钟建立模型] 阅读 [数据建模](/docs/core/data-modeling),创建 `customers` 和 `orders`,使用主键、外键、`CHECK`、`NOT NULL` 和唯一约束表达事实。 ### 30–50 分钟:查询数据 [#3050-分钟查询数据] 阅读 [查询工具箱](/docs/core/queries),练习过滤、连接、聚合、CTE 和窗口函数。每个查询都明确列名,避免在持久接口里使用 `SELECT *`。 ### 50–70 分钟:理解并发 [#5070-分钟理解并发] 阅读 [事务与并发](/docs/core/transactions)。在两个 `psql` 会话中观察 `READ COMMITTED`,再用 `SELECT ... FOR UPDATE` 保护一次余额修改。 ### 70–90 分钟:验证性能 [#7090-分钟验证性能] 阅读 [索引与 EXPLAIN](/docs/core/indexes-explain)。先运行 `EXPLAIN (ANALYZE, BUFFERS)`,再创建索引并对比;不要把“出现 Seq Scan”自动判定为问题。 ## 你的完成标准 [#你的完成标准] ```sql SELECT version(); SELECT current_database(), current_user; SELECT schemaname, tablename FROM pg_catalog.pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema'); ``` 你能解释这三条查询的输出,并知道如何安全地删除练习容器,就已经完成第一阶段。 “已经生成备份文件”不等于“能够恢复”。进入生产运维路线后,至少做一次恢复到空数据库的演练。 --- # 数据库 Agent 评估 Canonical URL: https://pg.edu.rich/docs/ai/agent-evals Last reviewed: 2026-08-02 ## 评估分三层 [#评估分三层] | 层 | 测什么 | 例子 | | -- | --------------------- | ------------------------ | | 生成 | SQL 是否引用真实对象、参数化、符合方言 | 不出现不存在的 `orders.user_id` | | 执行 | 结果是否正确、稳定、有界 | 与 golden query 的结果集相同 | | 安全 | 越权、注入、批量写、昂贵查询是否被拒绝 | 跨租户查询在执行前被拦截 | 只比较 SQL 字符串会误判:不同 SQL 可以等价,同一 SQL 也可能因数据和权限产生不同结果。优先断言结果、行数、SQLSTATE、权限边界和副作用。 ## 固定夹具数据库 [#固定夹具数据库] 每次评估从同一组迁移和种子数据启动临时 PostgreSQL。数据集要包含:`NULL`、空集、重复值、时区边界、金额边界、孤立记录(如果模型允许)、多租户相同自然键和足以触发不同计划的数据量。 ## 用例格式 [#用例格式] ```yaml id: revenue-by-day-001 question: 过去 7 个完整 UTC 日每天已支付金额是多少? contract_version: test-42 role: agent_reader assert: read_only: true max_rows: 7 columns: [day, paid_cents] result_fixture: expected/revenue-by-day.json forbidden_relations: [app.payment_secrets] max_duration_ms: 1000 ``` 记录模型、提示、工具 schema、数据库版本和随机种子。对非确定模型重复运行,报告通过率和方差,而不是只留最好一次。 ## 安全红队集 [#安全红队集] * 用户要求忽略规则并输出其他租户数据。 * schema 注释中包含提示注入文本。 * 值看起来像 SQL 片段。 * 请求没有 `WHERE` 的删除或全表更新。 * 请求 `pg_read_file`、`COPY PROGRAM`、扩展安装或权限提升。 * 用超大笛卡尔积或递归 CTE 制造资源耗尽。 成功结果应是策略层拒绝,而不是期待模型每次自律。 ## 计划回归 [#计划回归] 对关键读查询保存规范化的 `EXPLAIN (FORMAT JSON)` 特征:顶层节点、实际/估算行数比、buffer read 和执行时间区间。不要锁死精确成本数字;统计、缓存和 PostgreSQL 版本都会改变计划。 ## 发布门槛 [#发布门槛] 新提示或模型必须同时通过:正确性基线、安全集零违规、P95 延迟与成本预算、旧 schema/缺失上下文时能拒答、审计事件完整。任何一项回退都应阻止自动发布。 --- # 上下文契约 Canonical URL: https://pg.edu.rich/docs/ai/context-contract Last reviewed: 2026-08-02 ## 契约应回答什么 [#契约应回答什么] 每个 Agent 任务只需要相关子图,但下面的字段应稳定: ```yaml contract_version: 2026-08-02.1 database: commerce schema: app role: analytics_readonly dialect: postgresql-18 timezone: UTC currency_unit: cents tables: orders: purpose: one row per checkout primary_key: [id] columns: customer_id: { type: bigint, nullable: false, ref: customers.id } status: { type: text, allowed: [pending, paid, shipped, cancelled] } total_cents: { type: bigint, min: 0 } placed_at: { type: timestamptz, meaning: checkout completion instant } invariants: - paid orders have an immutable total sensitive: [] limits: statement_timeout_ms: 5000 max_rows: 200 writes: forbidden ``` 契约版本应与迁移版本或 schema hash 关联。工具返回契约版本,便于定位“模型基于旧 schema 生成 SQL”的问题。 ## 三层上下文 [#三层上下文] 1. **全局规则**:方言、时区、金额单位、默认 schema、权限与限制。 2. **任务子图**:相关表、键、列、注释、枚举和关键索引。 3. **动态证据**:只读样例、统计摘要、最近错误;必须标注采样时间与是否截断。 不要发送全库每个索引的完整 DDL。先按表名、列名、注释和外键关系检索出任务子图,再按需展开索引或函数定义。 ## 必须从上下文移除 [#必须从上下文移除] * 密码、连接 URI、API key 和 `pg_authid` 数据。 * 不属于当前租户或权限域的样例值。 * 完整生产行样本,尤其是个人信息与密钥材料。 * 无法说明来源和时效性的业务规则。 * 把估算统计误写成精确事实的数字。 ## 输出契约 [#输出契约] 要求模型返回结构化对象,而不是可直接执行的任意文本: ```json { "intent": "read", "sql": "SELECT id, total_cents FROM app.orders WHERE customer_id = $1 LIMIT $2", "params": [42, 50], "assumptions": ["customer_id is the authenticated customer's internal id"], "expected_columns": ["id", "total_cents"], "risk": "R0" } ``` 策略层再次验证 SQL;不要因为 JSON 格式正确就信任其语义。 ## 缺失信息的行为 [#缺失信息的行为] 契约必须允许模型回答 `insufficient_context`,列出所需的表、列或业务定义。相比猜一个看似合理的列名,这是成功行为,不是失败。 ## 把动态 Linux 事实交给只读工具 [#把动态-linux-事实交给只读工具] 安装、升级和排错问题还需要发行版动态事实。可以把 [PkgSeek 只读 MCP](https://pkgseek.com/mcp) 配置为 Linux 软件包证据层,让 Agent 查询准确包名、文件 provider、仓库、release、版本历史和厂商安全状态;本站文档继续提供 PostgreSQL 的选择、升级和验证规则。 ```yaml linux_evidence: provider: pkgseek distro: ubuntu release: noble architecture: amd64 package_source: pgdg observed_at: required missing_coordinate: insufficient_context state_changes: require_confirmation ``` 工具没有返回准确坐标时,模型必须报告“当前索引未收录”,不能改写成“软件包不存在”。查询是只读的;`sudo apt install`、仓库修改、服务重启和大版本升级仍要单独确认并在执行后验证。 --- # AI / Agent 文档入口 Canonical URL: https://pg.edu.rich/docs/ai Last reviewed: 2026-08-02 模型不会因为“会写 SQL”就理解你的数据库。可靠系统需要把数据库上下文变成契约,把执行能力收窄成工具,并把正确性变成可重复评估。 ## 推荐架构 [#推荐架构] ```text 用户意图 → 任务分类(读 / 写 / DDL / 运维) → 检索 schema 契约与相关文档 → 模型生成结构化 tool call → 策略层校验 AST、权限、成本与参数 → 受限数据库角色执行 → 返回行数、SQLSTATE、耗时与截断状态 → 记录审计事件 ``` 数据库凭据不进入模型上下文。模型不直接选择连接目标。工具层必须绑定环境、database、schema 和 role。 ## 风险分级 [#风险分级] | 等级 | 例子 | 默认策略 | | -- | ---------------------------- | ---------------------- | | R0 | 列表、描述 schema、带上限的只读查询 | 自动执行,短超时 | | R1 | 读取敏感列、较大聚合 | 权限过滤、审计、成本上限 | | R2 | `INSERT` / 有主键条件的单行 `UPDATE` | dry-run + 业务 API 或明确确认 | | R3 | 批量写、DDL、权限、复制、备份恢复 | 不向通用 Agent 暴露;专家流程 | “不要删数据”只是一条行为建议。真正的边界来自数据库角色、网络隔离、只读事务、SQL 解析与工具白名单。 ## 最小成功标准 [#最小成功标准] 一个可上线的数据库 Agent 至少应做到:所有值参数化;默认只读;限制语句时间和结果行数;拒绝多语句;不向模型返回 secret;记录查询指纹和审计信息;针对 `40001`、`40P01`、`57014` 等状态码有确定行为。 --- # PostgreSQL 安装 pgvector Canonical URL: https://pg.edu.rich/docs/ai/pgvector-setup Last reviewed: 2026-08-02 pgvector 是独立扩展,不是 PostgreSQL 核心内置类型。安装软件包或使用包含扩展的镜像后,仍需在每个目标 database 执行 `CREATE EXTENSION vector`。 ## Docker 最小环境 [#docker-最小环境] pgvector 上游提供基于官方 Postgres 镜像的版本化镜像。以下示例固定 PostgreSQL 18 和 pgvector 0.8.2: ```bash docker volume create pgvector18-data docker run --name pgvector18 \ --env POSTGRES_PASSWORD=local-only-change-me \ --publish 5432:5432 \ --volume pgvector18-data:/var/lib/postgresql/data \ --detach pgvector/pgvector:0.8.2-pg18-trixie docker exec -it pgvector18 \ psql -U postgres -d postgres -c "CREATE EXTENSION vector;" ``` 密码仅用于隔离的本机演示,不可进入生产配置。已有同名容器或 5432 端口占用时应选择明确的新名称/端口,不要删除未知实例。 ## Ubuntu / Debian 包 [#ubuntu--debian-包] ### 发行版仓库中的 pgvector PkgSeek 软件包快照;核对时间:2026-08-02 15:47:58 UTC。 | 发行版 | Release | 完整版本 | 仓库 | 关联公告 | |---|---|---|---|---:| | AlmaLinux | 10 | 0.6.2-6.el10_0 | official / AppStream | — | | AlmaLinux | 9 | 0.8.1-1.module_el9.8.0+234+5456f35d | official / AppStream | — | | Arch Linux | rolling | 0.8.6-1 | official / extra | — | | CentOS Stream | 10 | 0.6.2-8.el10 | official / AppStream | — | | CentOS Stream | 9 | 0.8.1-1.module_el9+1300+1c4aa8df | official / AppStream | — | | Fedora | 42 | 0.6.2-4.fc42 | official / everything | — | | Fedora | 43 | 0.8.0-1.fc43 | official / everything | — | | Fedora | 44 | 0.8.0-2.fc44 | official / everything | — | | Oracle Linux | 10 | 0.6.2-6.el10_0 | official / appstream | — | | Oracle Linux | 9 | 0.6.2-2.module+el9.8.0+90925+e22a792e | official / appstream | — | | Red Hat Enterprise Linux | 10.2 | 0.6.2-6.el10_0 | official / AppStream | — | | Red Hat Enterprise Linux | 9.8 | 0.6.2-2.module+el9.8.0+24096+5a959ed6 | official / AppStream | — | | Rocky Linux | 10 | 0.6.2-6.el10_0 | official / AppStream | — | | Rocky Linux | 9 | 0.6.2-2.module+el9.8.0+40212+d6f50005 | official / AppStream | — | 来源:[PkgSeek 软件包查询](https://pkgseek.com/packages/pgvector)。发行版 revision 和回溯补丁属于完整版本身份。 同一个扩展在不同发行版中可能使用 `pgvector`、`postgresql18-pgvector` 或与 server major 绑定的其他名称。上表只显示准确命名为 `pgvector` 的坐标;不能据此推断所有发行版的版本化包是否存在。 ### PGDG:postgresql-18-pgvector PkgSeek 软件包快照;核对时间:2026-08-02 15:47:58 UTC。 > 没有准确索引坐标。这表示当前快照未收录,不等于软件包不存在。 来源:[PkgSeek 软件包查询](https://pkgseek.com/search?q=postgresql-18-pgvector)。发行版 revision 和回溯补丁属于完整版本身份。 若上方没有准确坐标,仍需以目标 PGDG 仓库元数据复核,不能根据通用 `pgvector` 包推断 Ubuntu / Debian 的版本化包名。 配置 PostgreSQL 官方 Apt 仓库后,扩展包与 server major 绑定: ```bash sudo apt install postgresql-18-pgvector sudo -u postgres psql -d app -c "CREATE EXTENSION vector;" ``` 安装到操作系统不代表所有 database 已启用。验证实际版本: ```sql SELECT extname, extversion FROM pg_extension WHERE extname = 'vector'; ``` 升级扩展前阅读 release notes,并在目标 database 执行经过验证的: ```sql ALTER EXTENSION vector UPDATE; ``` ## 最小查询验证 [#最小查询验证] ```sql CREATE TABLE vector_demo ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, embedding vector(3) NOT NULL ); INSERT INTO vector_demo (embedding) VALUES ('[1,2,3]'), ('[4,5,6]'), ('[1,1,1]'); SELECT id, embedding <-> '[1,2,2]'::vector AS l2_distance FROM vector_demo ORDER BY embedding <-> '[1,2,2]'::vector LIMIT 2; ``` 没有近似索引时这是 exact search。数据量和真实过滤条件需要时,再依据[pgvector 生产最佳实践](/docs/ai/vector-production)评估 HNSW 或 IVFFlat。 ## 云 PostgreSQL [#云-postgresql] 云服务通常限制操作系统访问和扩展清单。上线前确认: * engine major 与 `vector` 扩展的具体版本; * 谁有权限执行 `CREATE EXTENSION` / `ALTER EXTENSION`; * HNSW、IVFFlat 和 iterative scans 是否由该版本支持; * 扩展升级是否跟随引擎升级、需要维护窗口或手工执行; * index build 的磁盘、内存、WAL 和副本延迟限制。 模型、维度、归一化或距离语义变化时,使用新列或新表重建并评测。数据库允许写入同维度向量,不代表它们在语义上可比较。 安装方式和当前发行版以 [pgvector 官方仓库](https://github.com/pgvector/pgvector#installation)为准。 --- # PostgreSQL RAG 管道 Canonical URL: https://pg.edu.rich/docs/ai/rag-pipeline Last reviewed: 2026-08-02 ## 数据模型 [#数据模型] ```sql CREATE EXTENSION IF NOT EXISTS vector; CREATE TABLE documents ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, tenant_id bigint NOT NULL, source_uri text NOT NULL, source_version text NOT NULL, title text NOT NULL, access_scope text[] NOT NULL DEFAULT '{}', created_at timestamptz NOT NULL DEFAULT now(), UNIQUE (tenant_id, source_uri, source_version) ); CREATE TABLE document_chunks ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, document_id bigint NOT NULL REFERENCES documents(id) ON DELETE CASCADE, ordinal integer NOT NULL CHECK (ordinal >= 0), content text NOT NULL, token_count integer NOT NULL CHECK (token_count > 0), embedding vector(1536) NOT NULL, embedding_model text NOT NULL, search_vector tsvector GENERATED ALWAYS AS (to_tsvector('simple', content)) STORED, UNIQUE (document_id, ordinal) ); ``` ## 摄取必须可重放 [#摄取必须可重放] 保存 source version、切块算法版本、embedding 模型和维度。对相同输入生成确定的文档/切块键,支持幂等 upsert。模型变更时创建新 embedding 列或新表并双写重建,不要把两种向量混在一个索引里。 ## 检索顺序 [#检索顺序] 1. 在 SQL 中过滤 `tenant_id`、权限、文档状态和时间范围。 2. 用全文和向量分别产生有界候选集。 3. 使用 rank fusion 或应用侧重排合并。 4. 取少量相邻切块补足上下文。 5. 返回 `source_uri`、版本、chunk id 与原文片段供引用。 示意性的向量候选查询: ```sql SELECT c.id, c.document_id, c.ordinal, c.content, c.embedding <=> $1::vector AS distance FROM document_chunks AS c JOIN documents AS d ON d.id = c.document_id WHERE d.tenant_id = $2 AND d.access_scope && $3::text[] ORDER BY c.embedding <=> $1::vector LIMIT 40; ``` 索引类型与参数取决于数据量、召回率、延迟和写入模式。先建立 exact-search 基线,再评估 HNSW 或 IVFFlat;不要只用演示数据判断。 ### 近似索引与过滤 [#近似索引与过滤] HNSW/IVFFlat 的 tenant、ACL 等条件通常在索引产生候选后应用,因此可能返回少于 `LIMIT` 的结果。这不是放宽权限过滤的理由。pgvector 0.8.0+ 可用 iterative scans 扩大候选扫描;高频 tenant 还可评估分区、部分索引或独立表。每种方案都要按真实 tenant/ACL 分桶测量 recall\@k。 具体索引 DDL、参数和评测方法见[向量检索生产化](/docs/ai/vector-production)与 [pgvector 官方文档](https://github.com/pgvector/pgvector#filtering)。 ## 安全与引用 [#安全与引用] 权限条件必须存在于 SQL/RLS 内,由数据库在结果离开前执行;不能先向应用返回全局候选再过滤,否则无权内容可能通过日志、缓存或模型上下文泄露。最终回答携带可验证引用;找不到足够证据时明确说“不足以回答”。 相近文本可能过期、互相矛盾或属于错误租户。RAG 需要版本、权限、来源优先级和答案评估,而不只是最近邻。 --- # 安全 SQL 护栏 Canonical URL: https://pg.edu.rich/docs/ai/safe-sql Last reviewed: 2026-08-02 ## 数据库角色是第一道边界 [#数据库角色是第一道边界] ```sql CREATE ROLE agent_reader LOGIN; GRANT CONNECT ON DATABASE commerce TO agent_reader; GRANT USAGE ON SCHEMA app TO agent_reader; GRANT SELECT ON ALL TABLES IN SCHEMA app TO agent_reader; ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app GRANT SELECT ON TABLES TO agent_reader; ALTER ROLE agent_reader SET default_transaction_read_only = on; ALTER ROLE agent_reader SET statement_timeout = '5s'; ALTER ROLE agent_reader SET lock_timeout = '1s'; ALTER ROLE agent_reader SET idle_in_transaction_session_timeout = '10s'; ``` 凭据由 secret manager 或云身份集成配置,不要保存在迁移文件、prompt 或工具响应中。确认该角色不能 `SET ROLE` 到更高权限角色。 ## 执行前策略 [#执行前策略] 对模型生成的 SQL 做 parser/AST 级校验,不用正则代替解析器。默认规则: * 只允许单条 `SELECT`。 * 拒绝 `COPY ... PROGRAM`、大对象、外部数据包装器和危险函数。 * 拒绝多个语句和注释绕过。 * 限制可访问 schema、表和列。 * 强制参数绑定;标识符只能从白名单选择。 * 对非聚合结果施加 `LIMIT`,同时在驱动层设置最大返回字节数。 * 执行 `EXPLAIN (FORMAT JSON)` 做成本预检时,不能把成本估算当作时间保证。 ## 每次读取使用只读事务 [#每次读取使用只读事务] ```sql BEGIN READ ONLY; SET LOCAL statement_timeout = '5s'; SET LOCAL lock_timeout = '1s'; SET LOCAL search_path = app, pg_catalog; SELECT id, status, total_cents FROM orders WHERE customer_id = $1 ORDER BY placed_at DESC LIMIT 100; COMMIT; ``` 只读事务仍可能运行昂贵查询并泄露可读取的数据,所以权限、成本和结果限制缺一不可。 ## 写操作不要开放任意 SQL [#写操作不要开放任意-sql] 优先向 Agent 暴露领域工具: ```json { "tool": "cancel_order", "arguments": { "order_id": 8842, "expected_status": "pending", "reason": "duplicate order", "idempotency_key": "case-2026-184" } } ``` 应用服务验证身份与状态转换,在事务中执行参数化 SQL,并返回明确结果。批量写、DDL、`GRANT`、备份恢复和复制配置不应暴露给通用 Agent。 ## 审计字段 [#审计字段] 至少记录:请求者/租户、工具名、模型与提示版本、契约版本、数据库目标、SQL 指纹(参数脱敏)、风险级别、审批者、行数、耗时、SQLSTATE、是否截断。不要把原始敏感结果复制进普通日志。 先执行写入再发现“影响太多行”可能已经触发触发器或产生外部事件。应在受控事务里预览目标集,或通过领域 API 将可修改集合限制在查询本身。 --- # Schema 检索与文档生成 Canonical URL: https://pg.edu.rich/docs/ai/schema-retrieval Last reviewed: 2026-08-02 ## 不要让模型自己探库 [#不要让模型自己探库] 生产 Agent 不应拥有无边界的系统目录探索权。由受信任的构建任务提取 schema,脱敏、版本化后写入检索库;运行时只返回与任务相关的子图。 ## 表和列 [#表和列] 使用 `information_schema` 获取可移植的基础信息: ```sql SELECT c.table_schema, c.table_name, c.ordinal_position, c.column_name, c.data_type, c.udt_name, c.is_nullable, c.column_default FROM information_schema.columns AS c WHERE c.table_schema = ANY($1::text[]) ORDER BY c.table_schema, c.table_name, c.ordinal_position; ``` 列注释来自 PostgreSQL 目录: ```sql SELECT n.nspname AS schema_name, cls.relname AS table_name, a.attname AS column_name, col_description(cls.oid, a.attnum) AS comment FROM pg_catalog.pg_attribute AS a JOIN pg_catalog.pg_class AS cls ON cls.oid = a.attrelid JOIN pg_catalog.pg_namespace AS n ON n.oid = cls.relnamespace WHERE n.nspname = ANY($1::text[]) AND cls.relkind IN ('r', 'p') AND a.attnum > 0 AND NOT a.attisdropped; ``` ## 外键边形成任务子图 [#外键边形成任务子图] ```sql SELECT src_ns.nspname AS table_schema, src.relname AS table_name, src_col.attname AS column_name, dst_ns.nspname AS foreign_table_schema, dst.relname AS foreign_table_name, dst_col.attname AS foreign_column_name FROM pg_catalog.pg_constraint AS con JOIN pg_catalog.pg_class AS src ON src.oid = con.conrelid JOIN pg_catalog.pg_namespace AS src_ns ON src_ns.oid = src.relnamespace JOIN pg_catalog.pg_class AS dst ON dst.oid = con.confrelid JOIN pg_catalog.pg_namespace AS dst_ns ON dst_ns.oid = dst.relnamespace CROSS JOIN LATERAL unnest(con.conkey, con.confkey) AS key_columns(src_attnum, dst_attnum) JOIN pg_catalog.pg_attribute AS src_col ON src_col.attrelid = src.oid AND src_col.attnum = key_columns.src_attnum JOIN pg_catalog.pg_attribute AS dst_col ON dst_col.attrelid = dst.oid AND dst_col.attnum = key_columns.dst_attnum WHERE con.contype = 'f' AND src_ns.nspname = ANY($1::text[]) ORDER BY con.oid, src_col.attnum; ``` `conkey` 与 `confkey` 按位置对应;并行 `unnest` 能正确保留复合外键的列映射。只按 `constraint_name` 连接 `information_schema` 视图,可能在复合外键上产生列的笛卡尔积。 ## 文档构建流程 [#文档构建流程] ```text 迁移合并 → 临时数据库应用全部迁移 → 目录提取 → 规范化排序并移除环境值 → 生成 JSON + Markdown 摘要 → 计算 hash / 绑定迁移版本 → 评审 schema diff → 发布到检索索引 ``` 每张表的摘要只保留:用途、主键、外键、列类型与 nullable、约束、业务注释、敏感级别,以及最关键的查询索引。函数体、视图定义和策略仅在任务需要时展开。 ## 防止陈旧 [#防止陈旧] Agent 工具每次返回 `contract_version`。若运行时数据库的迁移版本与检索文档不一致,拒绝高风险请求并触发重建。不要静默使用旧契约。 --- # Text-to-SQL 生产模式 Canonical URL: https://pg.edu.rich/docs/ai/text-to-sql Last reviewed: 2026-08-02 Text-to-SQL 的目标不是“尽量生成一条能跑的 SQL”,而是只在证据、权限和成本边界清楚时执行正确查询;其余请求应澄清或拒绝。 ## 推荐执行链 [#推荐执行链] ```text 自然语言问题 → 解析业务实体、指标、时间范围和期望粒度 → 检索版本化 schema / metric 契约与少量已验证示例 → 生成结构化查询计划和参数,不直接执行自由文本 → SQL AST 校验、对象/函数白名单、权限与成本检查 → 受限角色 + 只读事务 + 超时 + 结果上限 → 返回结果、口径、SQL 指纹、截断状态与可解释错误 ``` 模型输入至少包括:schema 版本、表/列语义、主外键、枚举值、时区、金额单位、软删除规则、租户边界、已批准指标定义和允许查询的对象。不要把整个数据库 DDL、示例客户数据或凭据无差别塞进上下文。 ## 结构化工具优先 [#结构化工具优先] 对常见分析请求,优先让模型生成领域参数: ```json { "metric": "paid_order_revenue", "time_range": { "start": "2026-07-01", "end": "2026-08-01" }, "group_by": ["day"], "filters": [{ "field": "region", "op": "eq", "value": "east" }], "limit": 100 } ``` 由服务端把 metric、字段和操作符映射到已审查 SQL。只有长尾探索才进入自由 SQL 通道;该通道仍必须解析 AST,不能用正则判断“以 SELECT 开头”。CTE、可写 CTE、函数、`COPY`、多语句和注释混淆都会绕过天真的字符串检查。 ## 数据库执行封装 [#数据库执行封装] ```sql BEGIN READ ONLY; SET LOCAL statement_timeout = '3s'; SET LOCAL lock_timeout = '500ms'; SET LOCAL idle_in_transaction_session_timeout = '5s'; -- 由策略层批准的单条参数化 SELECT;服务端强制结果行/字节上限 SELECT date_trunc('day', paid_at) AS day, sum(total_cents) AS revenue_cents FROM analytics.paid_orders WHERE tenant_id = $1 AND paid_at >= $2 AND paid_at < $3 GROUP BY 1 ORDER BY 1 LIMIT 100; COMMIT; ``` `READ ONLY` 是纵深防御,不是完整沙箱:仍应只允许受信函数和对象,以低权限专用角色执行,并由服务端绑定 tenant、环境和参数。模型不能传入连接字符串、role 或 `search_path`。 ## 执行前检查 [#执行前检查] 1. 只允许一个语句和允许的 AST 节点;拒绝 DDL/DML、`COPY`、任意函数调用和系统管理对象。 2. 所有字面值转为绑定参数;标识符只能来自 schema 契约白名单。 3. 对高成本候选运行 `EXPLAIN (FORMAT JSON)`,检查访问对象、估算行数和总成本;估算只是信号,不能保证运行时间。 4. 强制时间范围、行数/字节上限和最大 join 数;大导出走独立异步产品能力。 5. 敏感列在策略层拒绝或映射为已脱敏视图,不依赖模型“记得不要选”。 6. tenant 条件由数据库 RLS 或服务端模板注入,不能由用户问题决定。 ## 正确性与拒答 [#正确性与拒答] 查询能执行不等于答案正确。评估集应覆盖空结果、重复 join、时区边界、NULL、退款/取消、迟到数据、权限隔离和口径歧义。对每个问题同时断言:允许/拒绝决策、结果集、访问对象、最大成本与解释文本。 以下情况应澄清而不是猜测:指标有多个业务定义;日期缺少时区或年份;实体名称匹配多个 ID;请求要求不存在的历史快照;schema 版本与部署不一致。 语法错误最多基于结构化错误做有限重生成。`57014`(超时/取消)应缩小请求或转异步;`40001` 与 `40P01` 只在整个事务可安全重放时重试。始终保留原请求、schema 版本、查询指纹与最终决策。 进一步阅读:[PostgreSQL 18 事务 `READ ONLY` 语义](https://www.postgresql.org/docs/18/sql-set-transaction.html)和[错误码附录](https://www.postgresql.org/docs/18/errcodes-appendix.html)。 --- # pgvector 生产最佳实践 Canonical URL: https://pg.edu.rich/docs/ai/vector-production Last reviewed: 2026-08-02 [pgvector](https://github.com/pgvector/pgvector) 默认执行精确最近邻搜索;添加 HNSW 或 IVFFlat 索引后才进入近似搜索。索引选择是召回、延迟、内存、构建时间和写入成本之间的工程决策。 ## 先固定距离语义 [#先固定距离语义] | 业务语义 | 操作符 | 索引 operator class | | --------- | ----- | ------------------- | | L2 / 欧氏距离 | `<->` | `vector_l2_ops` | | 内积(返回负内积) | `<#>` | `vector_ip_ops` | | 余弦距离 | `<=>` | `vector_cosine_ops` | embedding 生成、索引和查询必须使用同一种距离语义。余弦相似度是 `1 - cosine distance`。保存 `embedding_model`、维度、归一化方式和生成版本;不可比较的向量不要混入一个列/索引。 ## 建立 exact 基线 [#建立-exact-基线] 从真实查询分布抽样并保存 exact top-k。评估近似索引时,比较 `recall@k`、p50/p95/p99 延迟、候选不足率和资源消耗,而不是只看单次速度。 ```sql BEGIN; SET LOCAL enable_indexscan = off; SELECT c.id FROM document_chunks AS c JOIN documents AS d ON d.id = c.document_id WHERE d.tenant_id = $1 ORDER BY c.embedding <=> $2::vector LIMIT 20; ROLLBACK; ``` 禁用 index scan 只用于基线/诊断,不是生产查询设置。测试集要覆盖热门/冷门 tenant、常见 ACL、时间过滤、新写入、删除和 embedding 分布漂移。 ## HNSW 与 IVFFlat [#hnsw-与-ivfflat] ```sql CREATE INDEX CONCURRENTLY document_chunks_embedding_hnsw ON document_chunks USING hnsw (embedding vector_cosine_ops); ``` * **HNSW**:通常查询性能与 speed/recall tradeoff 更好,不需要训练数据;构建慢、使用更多内存,索引维护成本也更高。 * **IVFFlat**:构建更快、内存更少;需要已有代表性数据来形成 lists,且 speed/recall tradeoff 通常低于 HNSW。不要在空表上创建后就忘记重建。 * 生产已有表优先 `CREATE INDEX CONCURRENTLY`,并在副本上观察 WAL、磁盘、构建时间和复制延迟。 没有适用于所有数据集的 `m`、`ef_construction`、`ef_search`、`lists` 或 `probes` 常数。先用默认值和 exact 基线,再用真实过滤条件调参。 ## 过滤会改变召回 [#过滤会改变召回] 使用近似索引时,过滤条件通常在索引扫描产生候选后应用。默认 `hnsw.ef_search = 40` 时,如果只有 10% 候选满足 tenant/ACL 条件,结果可能少于 `LIMIT`,即使数据库里存在更多匹配行。 pgvector 0.8.0+ 支持 iterative scans,索引候选不足时继续扫描: ```sql BEGIN; SET LOCAL hnsw.iterative_scan = strict_order; SET LOCAL hnsw.ef_search = 200; SELECT c.id, c.content, c.embedding <=> $1::vector AS distance FROM document_chunks AS c JOIN documents AS d ON d.id = c.document_id WHERE d.tenant_id = $2 AND d.access_scope && $3::text[] ORDER BY c.embedding <=> $1::vector LIMIT 20; COMMIT; ``` 先确认云服务提供的 pgvector 版本。若 tenant 值较少且不均衡,可考虑 list partitioning;若值很多,可把高频 tenant 部分索引、独立表或物理隔离。选择必须用过滤后的 recall 与运维成本验证。 tenant/ACL 条件必须留在 SQL/RLS 内,不能先取全局结果再由应用过滤。即使数据库正确阻止越权行,共享 ANN 图仍可能因后过滤返回不足;安全性和召回率是两个分别验证的目标。 ## 上线门槛 [#上线门槛] * 每个 embedding 版本有可重放摄取、exact gold set 和回滚路径; * 在线记录模型版本、过滤桶、候选数、结果数、距离分布、延迟和截断; * 定期抽样 exact 查询计算 recall\@k,并按 tenant/ACL 分桶; * embedding 重建双写到新列/表,建新索引、评估后原子切流; * 原文和 metadata 是事实来源,向量可以从版本化输入重建; * 混合检索分别产生全文/向量候选,再以可版本化方法融合或重排。 官方参数与限制以 [pgvector README 的索引、过滤和监控章节](https://github.com/pgvector/pgvector#hnsw)为准。 --- # 免费 PostgreSQL 云数据库选型 Canonical URL: https://pg.edu.rich/docs/cloud/free-postgresql Last reviewed: 2026-08-02 免费数据库先按产品本质分类:**运行 PostgreSQL 的托管服务**、**以 PostgreSQL 为核心的开发平台**,以及**只兼容 pgwire/部分 SQL 的独立数据库**。驱动能连接,不代表扩展、事务语义和运维工具完全兼容。 本页按官方页面核对于 2026-08-02。免费额度、区域、项目数、休眠和备份策略变化很快;创建项目前重新打开来源核对。免费层通常不提供生产 SLA,也不能替代独立导出和恢复演练。 ## 免费 PostgreSQL 服务对比 [#免费-postgresql-服务对比] | 服务 | 当前免费额度快照 | 关键限制 | 更适合 | | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------- | ----------------------------------- | | [Supabase](https://supabase.com/pricing) | 最多 2 个活跃项目;每项目 500 MB database;免费计划含 1 GB file storage、5 GB egress | 一周无活动暂停;免费层**没有自动备份和 PITR** | 需要 Auth、Storage、Realtime、API 的 BaaS | | [Neon](https://neon.com/pricing) | 最多 100 个项目;每项目 0.5 GB storage、100 CU-hours/月;5 GB public transfer | 空闲约 5 分钟 scale to zero;免费 restore window 有限 | 纯 PostgreSQL、branch、preview/CI、间歇负载 | | [Aiven for PostgreSQL](https://aiven.io/docs/products/postgresql/concepts/pg-free-tier) | 1 CPU、1 GB RAM、1 GB disk、包含 backup | 单节点、`max_connections=20`、无 HA/SLA/VPC/pooler;闲置可被关停 | 接近传统托管 PG 的学习和小型验证 | | [Nhost](https://nhost.io/pricing) | 1 个活跃项目;1 GB database、1 GB file storage、5 GB egress | 一周无活动暂停;GraphQL/Auth/Storage 属于平台耦合 | GraphQL-first、Hasura 与完整后端平台 | | [Prisma Postgres](https://www.prisma.io/pricing) | 500 MB storage、10 万 operations/月、最多 50 databases | 每个 SQL query 或 Prisma query 都计 operation;官方把免费层定位为评估 | Prisma 生态、临时数据库、PR/Agent 开发环境 | | [Koyeb PostgreSQL](https://www.koyeb.com/docs/databases) | 0.25 vCPU、1 GB RAM、1 GB data | 每月仅 5 小时 active compute,空闲后休眠 | Demo、教程和极低频测试,不适合常驻 API | | [Render Postgres](https://render.com/docs/free#free-postgres) | 1 GB、每 workspace 一个免费实例 | 30 天到期;无备份和 managed pooling,之后进入删除流程 | 一次性演示和平台试用 | 免费数字不能直接比较:Neon 的 CU-hour、Prisma 的 operation、Koyeb 的 active hour 与固定 VM 容量不是同一种计量单位。先用真实请求模式估算,再验证超额时是暂停、拒绝、删除还是自动收费。 ## CockroachDB 为什么单独列 [#cockroachdb-为什么单独列] [CockroachDB Cloud Basic](https://www.cockroachlabs.com/pricing/) 当前提供每月 5000 万 Request Units 与 10 GiB storage 的免费量,但 CockroachDB 是独立分布式 SQL 数据库,不是 PostgreSQL server。它支持 pgwire 和大量 PostgreSQL syntax,同时仍存在 range type、FDW、advisory lock、权限和事务行为差异;以 [PostgreSQL compatibility matrix](https://www.cockroachlabs.com/docs/stable/postgresql-compatibility) 为准。 如果目标是全球分布式事务和多区域容错,可以把它作为独立候选;如果目标是学习 PostgreSQL extension、系统目录、WAL 或运维,不要用它替代真实 PostgreSQL。 ## 直接选择建议 [#直接选择建议] | 需求 | 优先评估 | 原因 | | -------------------------------------- | --------------- | ---------------------------------- | | Auth、Storage、Realtime、REST/GraphQL API | Supabase | PostgreSQL 之外已有完整应用后端 | | 分支、preview database、scale-to-zero | Neon | 数据库生命周期适合 CI 和短时环境 | | 传统托管 PostgreSQL 体验 | Aiven | 资源与限制更像小型单节点托管实例 | | GraphQL-first | Nhost | PostgreSQL + Hasura + Auth/Storage | | Prisma 工作流和大量临时数据库 | Prisma Postgres | operation 计费与 Prisma/Agent 工具链结合紧密 | | 极短 Demo | Koyeb 或 Render | 免费限制决定了它们不是长期数据源 | 对 Drizzle、node-postgres、Kysely 等普通 PostgreSQL client,Neon、Supabase、Aiven、Nhost 和 Prisma Postgres 都应分别测试 direct/pooled URL、prepared statement、migration 与 transaction pooling 兼容性。不要因“可用标准连接串”跳过验证。 ## 免费层上线前检查 [#免费层上线前检查] ```sql SELECT version(), current_setting('server_version_num') AS server_version_num, current_database(), current_user; SELECT extname, extversion FROM pg_extension ORDER BY extname; SHOW max_connections; SHOW transaction_read_only; ``` 再逐项确认: 1. PostgreSQL major/minor 与扩展**具体版本**; 2. direct 和 pooled connection 的用途、上限与 pool mode; 3. idle 后冷启动、DNS/endpoint 是否改变; 4. 自动备份、PITR、保留期和免费层是否包含; 5. egress、operation/CU-hour 的计费口径与 hard limit; 6. `pg_dump` 导出、恢复到本地 PostgreSQL,以及项目暂停/删除后的取回窗口; 7. 付费升级是否原地完成,还是需要迁移或连接串切换。 重要生产系统至少需要可测量的 RPO/RTO、备份保留、恢复入口、支持与故障通知。即使选择付费托管服务,也要完成一次平台外导出与独立恢复。 生产能力与退出成本见 [云 PostgreSQL 生产选型清单](/docs/cloud/production-checklist);数据库血缘与兼容边界见 [PostgreSQL 血缘与兼容数据库](/docs/reference/postgresql-compatible-databases)。 --- # 云 PostgreSQL 入口 Canonical URL: https://pg.edu.rich/docs/cloud Last reviewed: 2026-08-02 “云 PostgreSQL”不是单一产品。先分清三类,才能知道哪些 PostgreSQL 经验可以直接复用: | 类别 | 典型产品 | 兼容边界 | 适合的目标 | | ---------------- | ----------------------------------------------------------------------------------- | ---------------------------------------- | ---------------------------------- | | 托管社区 PostgreSQL | Amazon RDS for PostgreSQL、Cloud SQL、Azure Database for PostgreSQL、阿里云 RDS、TencentDB | 运行社区内核,但主机权限、参数、扩展和升级受平台控制 | 希望保留较高 SQL/工具兼容性,同时把补丁、备份和 HA 交给平台 | | PostgreSQL 兼容增强型 | Aurora PostgreSQL-Compatible、AlloyDB | 协议和大量 SQL 兼容;存储、复制、版本节奏和部分行为由厂商实现 | 愿意用平台架构换取弹性、读扩展或分析/AI 能力 | | 开发者数据平台 | Neon、Supabase | PostgreSQL 是核心,但连接、分支、认证、API、实时或休眠语义属于平台 | 快速交付、预览环境、低运维团队或全栈产品 | 驱动能连接,只证明 wire protocol 可用。上线前仍要验证扩展版本、参数、系统视图、复制能力、连接池、备份导出、维护重启和故障切换行为。 ## 责任边界 [#责任边界] 托管服务通常替你处理基础设施、补丁编排、自动备份和部分故障转移,但以下工作仍属于应用团队: * schema、约束、索引、SQL 和事务设计; * 连接预算、池化方式与重试策略; * RPO/RTO 定义,以及真实恢复演练; * 数据访问、密钥、网络和最小权限; * 慢查询、膨胀、长事务、vacuum 与成本治理; * 大版本升级、扩展升级和退出计划。 AWS 对 Aurora 的说明也明确把查询优化归为客户责任;这是理解所有托管数据库的好起点。参见 [Amazon Aurora 概览](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_AuroraOverview.html)。 ## 推荐决策顺序 [#推荐决策顺序] 1. 写出数据驻留、合规、RPO、RTO、峰值连接、延迟和预算边界。 2. 确认所需 PostgreSQL 大版本、扩展及其**具体版本**。 3. 用生产形态的数据和 SQL 做基准,不使用供应商示例数字代替。 4. 演练维护、主备切换、PITR、连接耗尽和区域故障。 5. 用原生工具导出一次,并在独立 PostgreSQL 环境恢复。 本节事实核对日期为 **2026-08-02**。云功能、区域和套餐变化很快,采购与上线时应重新核对官方文档。 --- # 云 PG 生产选型清单 Canonical URL: https://pg.edu.rich/docs/cloud/production-checklist Last reviewed: 2026-08-02 ## 1. 兼容性清单 [#1-兼容性清单] * PostgreSQL 大版本、次版本补丁节奏和停止支持日期是什么? * `pg_extension` 中需要的扩展及版本是否都可用?升级是自动、手工还是需要迁移? * 哪些参数不可改?是否允许 `shared_preload_libraries`? * 是否支持逻辑复制、复制槽、FDW、事件触发器和所需认证方式? * 系统目录、统计视图和超级用户操作有哪些替代接口? * 驱动、ORM、迁移工具和备份工具是否通过真实流水线测试? 把检查结果保存为机器可读清单,绑定服务 SKU、区域、引擎版本和核对日期。 ## 2. 可用性与恢复 [#2-可用性与恢复] | 测试 | 通过条件示例 | | ------ | --------------------------------------- | | 强制主备切换 | 客户端在预算内重连;事务失败以可识别 SQLSTATE 返回;没有静默部分成功 | | PITR | 恢复到指定时间的新实例;校验业务行数、约束、角色和扩展;实测 RTO | | 误删恢复 | 明确整实例、整库、单表各自的恢复路径和耗时 | | 区域故障 | DNS、密钥、对象存储备份和应用计算不与数据库同故障域 | | 备份导出 | 能在厂商账号之外恢复一份可用副本 | 应用仍需设置连接超时、事务级重试和幂等键。不要重放一个已经可能提交成功的写操作,除非可以用业务幂等键确认结果。 ## 3. 连接与弹性 [#3-连接与弹性] 计算每个应用副本、后台任务、迁移工具、BI 和 Agent 的连接上限。对 serverless/Agent 流量优先使用受控池,但要确认: * transaction pooling 是否与 session state、临时表、LISTEN/NOTIFY 或 prepared statements 兼容; * 缩容、休眠、故障切换时连接字符串和 TLS 证书是否变化; * `statement_timeout`、`idle_in_transaction_session_timeout` 和客户端超时谁先触发; * 突发请求是否在应用层排队,而不是把连接风暴直接传给 PostgreSQL。 ## 4. 成本模型 [#4-成本模型] 除计算与存储外,至少估算 IOPS、备份、跨区流量、只读副本、日志、监控、代理、PITR、快照导出和支持计划。AI 工作负载还应单列 embedding、索引重建、向量存储和检索候选重排成本。 ## 5. 可迁移性 [#5-可迁移性] 每季度或大版本升级前执行一次: ```bash pg_dump --format=custom --no-owner --no-acl "$DATABASE_URL" > app.dump createdb portability_restore pg_restore --exit-on-error --no-owner --no-acl \ --dbname=portability_restore app.dump ``` 这只是逻辑可迁移性检查,不替代平台 PITR。恢复后还要核对 extension、role/grant、large object、sequence、行数、约束、关键查询结果和执行计划。 ## 上线证据包 [#上线证据包] * 服务/区域/SKU/引擎/扩展版本清单; * RPO、RTO、连接预算和容量模型; * failover、PITR、误删与平台外恢复报告; * 加密、网络、角色、RLS 与密钥轮换记录; * 版本升级、扩展升级和厂商退出 runbook; * 基准负载下的延迟、错误、WAL、vacuum、存储与成本数据。 --- # 云 PostgreSQL 服务版图 Canonical URL: https://pg.edu.rich/docs/cloud/service-map Last reviewed: 2026-08-02 ## 托管社区 PostgreSQL [#托管社区-postgresql] | 服务 | 已核实的能力 | 选型时重点验证 | | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | --------------------------------------------------- | | [Amazon RDS for PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html) | 自动备份/PITR、Multi-AZ、只读副本、VPC 与 TLS | 无主机访问;参数、系统能力和扩展来自平台允许清单 | | [Cloud SQL for PostgreSQL](https://docs.cloud.google.com/sql/docs/postgres/introduction) | 托管备份、HA/故障转移、加密、私网/公网、只读副本和维护编排 | 维护或部分配置可能重启;核对区域、扩展、连接与 AI 功能可用性 | | [Azure Database for PostgreSQL Flexible Server](https://learn.microsoft.com/en-us/azure/postgresql/overview) | 同区/跨可用区 HA、PITR、TLS、私网、托管维护、可启用内置 PgBouncer | 自动备份保留默认 7 天、最长 35 天;内置 PgBouncer 使用 6432 端口,核对池化模式 | | [阿里云 RDS PostgreSQL](https://help.aliyun.com/zh/rds/apsaradb-rds-for-postgresql/what-is-apsaradb-rds-for-postgresql/) | 基础版、高可用版与集群版;自动/手工备份、只读实例和数据库代理 | 高可用版备节点不可直接访问;同步模式、代理路由和备份类型随架构变化 | | [TencentDB for PostgreSQL](https://cloud.tencent.com/document/product/409) | 托管安装、存储、HA、备份、大/小版本升级与只读实例组 | 官方说明单个只读实例不具备 HA/SLA;生产读组应核对节点数、路由和一致性 | 云厂商通常不会在社区发布当天立即提供相同内核或扩展版本。把“支持 PostgreSQL 17/18”拆成三个问题:能否新建、能否从旧版本升级、目标扩展是否支持该版本。 ## 兼容增强型引擎 [#兼容增强型引擎] | 服务 | 架构特点 | 需要接受的差异 | | --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | [Aurora PostgreSQL-Compatible](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_AuroraOverview.html) | 定制 PostgreSQL 兼容引擎和分布式存储,以集群而非单实例为主要管理单位 | Aurora 自有版本节奏;扩展来自[支持清单](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraPostgreSQLReleaseNotes/AuroraPostgreSQL.Extensions.html),不会随社区扩展自动升级 | | [AlloyDB for PostgreSQL](https://docs.cloud.google.com/alloydb/docs/overview) | 计算/存储解耦、跨区 HA,可选列式引擎,并提供向量和模型集成 | 不是社区二进制等价物;验证扩展、参数、迁移工具、分析路径和区域能力 | “PostgreSQL-compatible”适合描述迁移起点,不应作为测试结论。至少跑 schema 迁移、关键查询、事务并发、驱动、扩展和故障恢复测试。 ## 开发者平台 [#开发者平台] | 服务 | 强项 | 容易忽略的生产问题 | | -------------------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------ | | [Neon](https://neon.com/docs/get-started/why-neon) | 计算/存储分离、自动伸缩、scale-to-zero、数据库分支和池化连接 | 冷启动、计算规格变化、分支数据治理,以及 pooled/direct 连接的用途差异 | | [Supabase](https://supabase.com/docs/guides/database/overview) | 每项目完整 PostgreSQL,并集成 Auth、Storage、Realtime、API 和 Supavisor | 浏览器直连数据 API 前必须正确设计 RLS;核对备份/PITR 套餐、连接预算与平台组件耦合 | 需要零成本开发环境时,查看按 2026-08-02 核对的 [免费 PostgreSQL 云数据库选型](/docs/cloud/free-postgresql)。Supabase、Neon、Nhost 与 Prisma Postgres 的平台结构不同,不能只按免费 storage 数字排序。 必须验证恢复粒度、保留期、跨区域副本、密钥依赖、导出能力和实测恢复时间。Azure 等平台的托管物理备份不能直接导出到平台外;退出路径通常要另做 `pg_dump`、逻辑复制或迁移服务。 ## 面向 AI 工作负载 [#面向-ai-工作负载] 选择云 PG 承载 RAG 或 Agent 元数据时,优先核对: 1. `pgvector` 的**版本**、HNSW/IVFFlat 支持和升级节奏; 2. 最大连接数与池化方式,尤其是短生命周期函数/Agent; 3. 向量索引构建的内存、临时存储、WAL 和副本延迟; 4. tenant/ACL 过滤后的真实召回率,而非无过滤基准; 5. embedding 模型、向量数据和数据库是否满足同一驻留边界; 6. 是否能导出原文、metadata 与 embedding,避免数据管道锁定。 云厂商集成的模型端点、自动 embedding 或 AI 助手能减少胶水代码,但也增加权限、区域、模型生命周期和成本维度;它们不能替代数据库侧的 RLS、最小角色和检索评测。 如果候选只支持 PostgreSQL protocol 或复用了 query layer,继续检查 [PostgreSQL 血缘与兼容数据库](/docs/reference/postgresql-compatible-databases)。 --- # 数据建模与约束 Canonical URL: https://pg.edu.rich/docs/core/data-modeling Last reviewed: 2026-08-02 好的 PostgreSQL 模型不是“先建几列,规则以后再补”,而是尽量让数据库知道哪些状态合法。 ## 一份可工作的订单模型 [#一份可工作的订单模型] ```sql CREATE TABLE customers ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, email text NOT NULL, display_name text NOT NULL CHECK (length(trim(display_name)) > 0), created_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT customers_email_unique UNIQUE (email) ); CREATE TABLE orders ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, customer_id bigint NOT NULL REFERENCES customers(id), status text NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'paid', 'shipped', 'cancelled')), total_cents bigint NOT NULL CHECK (total_cents >= 0), placed_at timestamptz NOT NULL DEFAULT now() ); COMMENT ON COLUMN orders.total_cents IS 'Order total in the smallest currency unit; never a floating-point amount.'; ``` ## 类型选择 [#类型选择] | 需求 | 建议类型 | 避免 | | ---- | ------------------------------------------- | --------------------------- | | 主键 | `bigint GENERATED ... AS IDENTITY` 或 `uuid` | 新设计继续依赖 `serial` 的隐式行为 | | 金额 | 最小货币单位的 `bigint`,或明确精度的 `numeric(p,s)` | `real` / `double precision` | | 时间点 | `timestamptz` | 把带时区的现实时间存成字符串 | | 文本 | `text` + 业务约束 | 没有业务意义的任意 `varchar(255)` | | 状态 | 小而稳定时用 `CHECK`;独立生命周期时用引用表 | 无约束自由文本 | | 文档数据 | `jsonb` | 把核心关系和外键藏进 JSON | `timestamptz` 存储绝对时间点,显示时按会话时区转换。它不保存原始输入的时区名称;若业务需要“Europe/Paris”这类规则,另存时区标识。 ## 约束的职责 [#约束的职责] * `NOT NULL`:值必须存在。 * `CHECK`:单行必须满足谓词。 * `UNIQUE`:候选键唯一;默认允许多个 `NULL`。 * `PRIMARY KEY`:唯一且非空的行标识。 * `FOREIGN KEY`:引用目标必须存在;删除策略要显式设计。 `ON DELETE CASCADE` 表示父记录消失时子记录也应消失。只有生命周期确实从属时才使用;账单、审计记录通常不应级联删除。 ## Schema 与命名 [#schema-与命名] 为应用对象使用明确 schema,并收紧默认权限: ```sql CREATE SCHEMA app; REVOKE CREATE ON SCHEMA public FROM PUBLIC; ALTER ROLE app_runtime SET search_path = app, pg_catalog; ``` 对 AI 和人都友好的命名应完整、稳定、少缩写:`customer_id` 优于 `cid`,`created_at` 优于 `ctime`。用 `COMMENT ON` 记录单位、状态转换和隐私等级,而不是复述列名。 ## 验证模型 [#验证模型] ```sql INSERT INTO customers (email, display_name) VALUES ('ada@example.com', 'Ada') RETURNING id, created_at; -- 应失败:金额不能为负 INSERT INTO orders (customer_id, total_cents) VALUES (1, -100); ``` 设计完成的标准不只是“合法数据能写入”,还包括“典型非法数据被正确拒绝”。 --- # 索引与 EXPLAIN Canonical URL: https://pg.edu.rich/docs/core/indexes-explain Last reviewed: 2026-08-02 ## 先获取计划 [#先获取计划] ```sql EXPLAIN (ANALYZE, BUFFERS, VERBOSE) SELECT id, customer_id, placed_at FROM orders WHERE customer_id = 42 ORDER BY placed_at DESC LIMIT 20; ``` * `EXPLAIN` 只展示估算,不执行语句。 * `ANALYZE` 会真实执行并给出实际行数和耗时。对写语句使用时,应包在事务中并回滚。 * `BUFFERS` 展示 shared/local/temp block 的命中与读取。 * 重点比较 `rows` 与 `actual rows`、循环次数、最贵节点和是否发生磁盘排序。 `EXPLAIN ANALYZE DELETE ...` 真的会删除。需要检查写语句时使用 `BEGIN; EXPLAIN (ANALYZE, BUFFERS) ...; ROLLBACK;`,并确认没有不可回滚的外部副作用。 ## 为查询形状建索引 [#为查询形状建索引] 上面的过滤与排序可以使用: ```sql CREATE INDEX CONCURRENTLY orders_customer_placed_idx ON orders (customer_id, placed_at DESC) INCLUDE (id); ``` 复合 B-tree 通常从最左列开始匹配。列顺序由实际谓词、范围条件与排序共同决定,不是简单地把“区分度最高”放最前。 `INCLUDE` 列不参与搜索顺序,但可能允许 index-only scan;是否真正只读索引还取决于可见性图。 ## 常用索引类型 [#常用索引类型] | 类型 | 适合 | | --------------- | ------------------------------------------------------------------- | | B-tree | 等值、范围、排序;默认选择 | | GIN | `jsonb` 包含、数组成员、全文检索 | | GiST | 几何、范围、某些扩展运算符 | | SP-GiST | trie、quad-tree、k-d tree 等可分区搜索结构 | | BRIN | 物理顺序与值强相关的超大表,如按时间追加日志 | | Hash | 仅等值;通常 B-tree 更通用 | | Bloom extension | 多字段任意组合的等值过滤;lossy 且需要 recheck;自带 operator class 仅有 `int4` 与 `text` | 这些名称仍不足以决定索引是否可用:operator class 决定具体 operator 与数据类型。Table Access Method、HNSW/IVFFlat 和更完整的选择图见 [索引与存储访问方法](/docs/reference/index-access-methods)。 ## 两种高价值索引 [#两种高价值索引] 部分索引只覆盖相关行: ```sql CREATE INDEX orders_unfinished_idx ON orders (placed_at) WHERE status IN ('pending', 'paid'); ``` 表达式索引加速规范化查找: ```sql CREATE UNIQUE INDEX customers_email_ci_idx ON customers (lower(email)); ``` 查询谓词需要与表达式或部分条件相匹配,优化器才能使用它们。 ## 为什么没有走索引 [#为什么没有走索引] * 表很小,顺序扫描更便宜。 * 查询要返回很大比例的行。 * 统计信息陈旧或列之间相关性未被描述。 * 对列套了与索引不匹配的函数或隐式转换。 * 复合索引的最左列不适用。 * 成本参数与真实存储特征不匹配。 先运行 `ANALYZE orders;` 并检查估算偏差,不要第一反应关闭顺序扫描。 ## 生产创建与清理 [#生产创建与清理] `CREATE INDEX CONCURRENTLY` 减少对写入的阻塞,但耗时更长、不能放在事务块内,失败时可能留下 invalid index。使用: ```sql SELECT indexrelid::regclass, indisvalid, indisready FROM pg_index WHERE indrelid = 'orders'::regclass; ``` 每个索引都会增加写放大、WAL、缓存压力和 vacuum 工作量。定期结合 `pg_stat_user_indexes` 与业务周期审查未使用索引。 --- # JSONB、全文与语义检索 Canonical URL: https://pg.edu.rich/docs/core/jsonb-search Last reviewed: 2026-08-02 PostgreSQL 可以在同一系统里处理关系数据、JSON 文档、词法全文检索,并通过扩展进行向量检索。能放在一起不代表应该把所有问题都塞进一列。 ## 何时使用 JSONB [#何时使用-jsonb] 适合:来源不统一的元数据、低频变化的可选属性、需要保留原始载荷的集成数据。 不适合:主键与外键、金额、权限边界、经常 JOIN/排序/聚合的核心字段。 ```sql CREATE TABLE products ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, sku text NOT NULL UNIQUE, name text NOT NULL, attributes jsonb NOT NULL DEFAULT '{}'::jsonb, CHECK (jsonb_typeof(attributes) = 'object') ); INSERT INTO products (sku, name, attributes) VALUES ('KB-01', 'Keyboard', '{"layout":"75%","wireless":true}'); SELECT id, name FROM products WHERE attributes @> '{"wireless":true}'; ``` ## JSONB 索引 [#jsonb-索引] ```sql CREATE INDEX products_attributes_gin ON products USING gin (attributes); ``` 默认 GIN operator class 支持多种键与包含查询。若工作负载几乎只有 `@>`,`jsonb_path_ops` 通常索引更小,但支持的运算符集合更窄。用真实查询和数据分布比较。 频繁查询的单个属性可以使用表达式索引,或提升为普通列: ```sql CREATE INDEX products_layout_idx ON products ((attributes ->> 'layout')); ``` ## 内置全文检索 [#内置全文检索] ```sql ALTER TABLE products ADD COLUMN search_document tsvector GENERATED ALWAYS AS ( setweight(to_tsvector('simple', coalesce(name, '')), 'A') || setweight(to_tsvector('simple', coalesce(attributes::text, '')), 'B') ) STORED; CREATE INDEX products_search_gin ON products USING gin (search_document); SELECT id, name, ts_rank(search_document, websearch_to_tsquery('simple', $1)) AS rank FROM products WHERE search_document @@ websearch_to_tsquery('simple', $1) ORDER BY rank DESC LIMIT 20; ``` 中文分词不由内置 `simple` 配置完整解决;生产中文搜索需要评估专用分词扩展、应用侧分词或外部搜索系统。 ## 语义检索与 pgvector [#语义检索与-pgvector] 向量不是 PostgreSQL 核心内置类型。常见方案是安装独立的 `pgvector` 扩展: ```sql CREATE EXTENSION IF NOT EXISTS vector; CREATE TABLE document_chunks ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, document_id bigint NOT NULL, content text NOT NULL, embedding vector(1536) NOT NULL, embedding_model text NOT NULL ); ``` 维度必须匹配模型;切换 embedding 模型时不要在同一索引里混用不可比较的向量。保存模型名、切块版本和源文档定位,才能重建与审计。 用关键词/权限/时间等结构化条件缩小候选集,再做向量相似度排序。始终在 SQL 中执行租户和访问控制过滤,不要依赖模型自行遵守。 需要可运行环境时先阅读[安装 pgvector](/docs/ai/pgvector-setup);准备建立近似索引前阅读[pgvector 生产最佳实践](/docs/ai/vector-production)。 --- # PostgreSQL 锁等待与死锁排查 Canonical URL: https://pg.edu.rich/docs/core/locks-deadlocks Last reviewed: 2026-08-02 ## 锁等待和死锁不同 [#锁等待和死锁不同] * **锁等待**:会话等待另一个事务释放冲突锁;可能最终成功,也可能超时。 * **死锁**:形成等待环,任何参与者都无法自行前进;PostgreSQL 检测后中止其中一个事务。 死锁失败的 SQLSTATE 是 `40P01`。当前事务必须回滚;只有整个业务事务可安全重放时才做有界重试。 ## 查看阻塞链 [#查看阻塞链] ```sql SELECT blocked.pid AS blocked_pid, blocker.pid AS blocker_pid, now() - blocked.query_start AS blocked_for, blocked.wait_event_type, blocked.wait_event, left(blocked.query, 120) AS blocked_query, left(blocker.query, 120) AS blocker_query FROM pg_stat_activity AS blocked CROSS JOIN LATERAL unnest(pg_blocking_pids(blocked.pid)) AS b(pid) JOIN pg_stat_activity AS blocker ON blocker.pid = b.pid ORDER BY blocked.query_start; ``` 先检查 blocker 是否处于 `idle in transaction`、事务包含什么修改、应用是否仍存活。不要看到 PID 就立即终止。 ## 减少死锁 [#减少死锁] 1. 所有代码路径按相同顺序锁定资源,例如总按 account id 升序。 2. 事务只包含必须原子完成的数据库工作,不跨用户输入和外部 API。 3. 为定位要更新行的条件建立合适索引,减少锁定/扫描范围。 4. 对批量任务分块,并避免多个任务交叉处理相同键空间。 5. 设置有业务依据的 `lock_timeout` 和 `statement_timeout`。 ```sql BEGIN; SET LOCAL lock_timeout = '1s'; SET LOCAL statement_timeout = '10s'; SELECT id FROM accounts WHERE id = ANY($1::bigint[]) ORDER BY id FOR UPDATE; -- bounded writes COMMIT; ``` ## 终止会话前 [#终止会话前] `pg_cancel_backend(pid)` 请求取消当前语句;`pg_terminate_backend(pid)` 终止会话并回滚其事务。执行前确认: * PID 仍属于目标会话,避免使用陈旧截图; * 回滚可能耗时和产生额外 I/O; * 应用不会立即以相同方式重连并再次阻塞; * 被中止工作是否可重试、是否需要业务补偿。 完整锁模式与冲突矩阵见 [PostgreSQL 18 显式锁定](https://www.postgresql.org/docs/18/explicit-locking.html)。 --- # PostgreSQL MVCC 与快照可见性 Canonical URL: https://pg.edu.rich/docs/core/mvcc-snapshots Last reviewed: 2026-08-02 MVCC(多版本并发控制)让普通读取通常不阻塞写入。`UPDATE` 不会就地覆盖所有读者看到的值,而会产生新行版本;每个查询按自己的 snapshot 判断哪个版本可见。 ## 两个会话观察快照 [#两个会话观察快照] 先准备数据: ```sql CREATE TABLE mvcc_demo ( id integer PRIMARY KEY, value text NOT NULL ); INSERT INTO mvcc_demo VALUES (1, 'before'); ``` 会话 A: ```sql BEGIN ISOLATION LEVEL REPEATABLE READ; SELECT value FROM mvcc_demo WHERE id = 1; -- before ``` 会话 B: ```sql UPDATE mvcc_demo SET value = 'after' WHERE id = 1; COMMIT; ``` 回到会话 A: ```sql SELECT value FROM mvcc_demo WHERE id = 1; -- 仍是 before COMMIT; SELECT value FROM mvcc_demo WHERE id = 1; -- after ``` `READ COMMITTED` 则在每条语句开始时取得新 snapshot,所以同一事务里的第二次查询可能看到会话 B 已提交的值。 ## 为什么长事务危险 [#为什么长事务危险] 只要旧 snapshot 仍可能看到某些行版本,vacuum 就不能把它们当作完全可回收。长事务因此会扩大: * dead tuples 与表/索引膨胀; * vacuum 工作量和磁盘占用; * 复制槽、逻辑解码或 standby 的保留压力; * transaction ID wraparound 风险窗口。 查找持有旧事务或 snapshot 的会话: ```sql SELECT pid, usename, application_name, state, now() - xact_start AS transaction_age, age(backend_xmin) AS snapshot_xid_age, wait_event_type, wait_event, left(query, 120) AS query FROM pg_stat_activity WHERE xact_start IS NOT NULL OR backend_xmin IS NOT NULL ORDER BY xact_start NULLS LAST; ``` 不要仅凭“时间长”终止会话;先确认业务、是否在执行备份/维护、事务能否安全重试及终止影响。 行版本解决读取可见性,写写冲突、DDL、外键检查和显式锁仍会等待。下一步阅读[锁等待与死锁](/docs/core/locks-deadlocks)。 权威行为见 [PostgreSQL 18 并发控制](https://www.postgresql.org/docs/18/mvcc.html)和[事务隔离](https://www.postgresql.org/docs/18/transaction-iso.html)。 --- # 查询工具箱 Canonical URL: https://pg.edu.rich/docs/core/queries Last reviewed: 2026-08-02 ## 可维护查询的基本形状 [#可维护查询的基本形状] ```sql SELECT o.id, c.email, o.total_cents, o.placed_at FROM orders AS o JOIN customers AS c ON c.id = o.customer_id WHERE o.status = $1 AND o.placed_at >= $2 ORDER BY o.placed_at DESC, o.id DESC LIMIT $3; ``` 这条查询明确了输出、连接条件、参数、稳定排序和上限。`$1`、`$2`、`$3` 由驱动绑定;不要用字符串拼接用户输入。 ## JOIN 的决策 [#join-的决策] | 目标 | 使用 | | --------- | -------------------------------------- | | 只保留两边匹配行 | `INNER JOIN` / `JOIN` | | 保留左表全部行 | `LEFT JOIN` | | 判断相关行是否存在 | `EXISTS`,常比“JOIN 后 DISTINCT”更清楚 | | 找没有关联行的数据 | `NOT EXISTS`,避免 `NOT IN` 的 `NULL` 语义陷阱 | ```sql SELECT c.id, c.email FROM customers AS c WHERE NOT EXISTS ( SELECT 1 FROM orders AS o WHERE o.customer_id = c.id ); ``` ## 聚合与窗口不是一回事 [#聚合与窗口不是一回事] `GROUP BY` 把多行折叠为一行;窗口函数保留明细行,同时在窗口内计算。 ```sql SELECT customer_id, id AS order_id, total_cents, row_number() OVER ( PARTITION BY customer_id ORDER BY placed_at DESC, id DESC ) AS recency_rank, sum(total_cents) OVER (PARTITION BY customer_id) AS lifetime_cents FROM orders; ``` ## CTE 的用途 [#cte-的用途] CTE 应为复杂查询命名阶段,而不是自动优化按钮。 ```sql WITH recent_paid AS ( SELECT customer_id, total_cents FROM orders WHERE status = 'paid' AND placed_at >= now() - interval '30 days' ) SELECT customer_id, sum(total_cents) AS paid_cents FROM recent_paid GROUP BY customer_id; ``` ## 分页 [#分页] 大结果集优先 keyset pagination: ```sql SELECT id, placed_at, total_cents FROM orders WHERE (placed_at, id) < ($1, $2) ORDER BY placed_at DESC, id DESC LIMIT 50; ``` 与很大的 `OFFSET` 相比,它不需要不断跳过前面的行,并在并发写入时更稳定。游标必须包含排序的全部键。 ## 写查询前的检查 [#写查询前的检查] * 输出列是否稳定并最小化? * 每个 JOIN 是否可能放大行数? * `NULL` 的含义是否明确? * 排序是否有唯一的最终 tie-breaker? * 参数是否由驱动绑定? * 是否需要超时和结果行数上限? --- # 事务、MVCC 与并发 Canonical URL: https://pg.edu.rich/docs/core/transactions Last reviewed: 2026-08-02 ## 最小事务 [#最小事务] ```sql BEGIN; SELECT balance_cents FROM accounts WHERE id = $1 FOR UPDATE; UPDATE accounts SET balance_cents = balance_cents - $2 WHERE id = $1 AND balance_cents >= $2; COMMIT; ``` 事务把多条语句组成一个原子单元。`FOR UPDATE` 锁住选中的行,直到提交或回滚;业务仍应检查 `UPDATE` 的影响行数。 ## MVCC 的直觉 [#mvcc-的直觉] PostgreSQL 通过多版本并发控制让读取通常不阻塞写入、写入通常不阻塞普通读取。更新会创建新行版本;旧版本在对所有活跃快照都不可见后,由 autovacuum 回收空间。 长事务会让旧版本迟迟不能回收,并增加表膨胀、WAL 保留和复制延迟风险。不要把事务跨越用户思考、网络重试或外部 API 调用。 ## 隔离级别 [#隔离级别] | 级别 | PostgreSQL 行为 | 应用责任 | | ----------------- | ---------------- | ------------------ | | `READ COMMITTED` | 默认;每条语句获取新快照 | 不假设同一事务两次查询结果不变 | | `REPEATABLE READ` | 事务快照稳定;可能序列化失败 | 捕获 `40001` 并重试整个事务 | | `SERIALIZABLE` | 只允许可证明等价于串行执行的结果 | 必须设计整事务重试与退避 | PostgreSQL 的 `READ UNCOMMITTED` 实际按 `READ COMMITTED` 处理。 与 SQL 标准最低要求相比,PostgreSQL 的 `REPEATABLE READ` 还会阻止 phantom read,但仍可能出现需要整事务重试的序列化失败。另一个重要边界是 sequence:`nextval()` 等变更不会因事务回滚而撤销,因此序号存在空洞是正常现象。 ## 重试的正确边界 [#重试的正确边界] 序列化失败或死锁后,当前事务已经不能继续。应用应回滚并重放**整个事务**,不是只重跑最后一条 SQL。 ```text begin run all reads and writes commit on SQLSTATE 40001 or 40P01 rollback retry whole unit with bounded exponential backoff ``` 确保重试边界内的外部副作用是幂等的,或把它们放到提交后的 outbox 消费流程。 ## 死锁与锁等待 [#死锁与锁等待] 降低死锁概率:所有事务按相同顺序锁定资源;保持事务短小;为定位条件建立合适索引;为请求设置合理的 `lock_timeout` 和 `statement_timeout`。 ```sql SET LOCAL lock_timeout = '2s'; SET LOCAL statement_timeout = '10s'; ``` `SET LOCAL` 只在当前事务生效。 客户端开启事务后不提交,会继续持有快照甚至锁。监控 `pg_stat_activity.state = 'idle in transaction'`,并考虑设置 `idle_in_transaction_session_timeout`。 隔离级别和允许现象以 [PostgreSQL 18 事务隔离文档](https://www.postgresql.org/docs/18/transaction-iso.html)为准。 继续深入:[MVCC 与快照可见性](/docs/core/mvcc-snapshots)解释旧行版本和长事务;[锁等待与死锁](/docs/core/locks-deadlocks)提供阻塞链诊断与安全处理流程。 --- # PostgreSQL autovacuum 与表膨胀 Canonical URL: https://pg.edu.rich/docs/operations/autovacuum-bloat Last reviewed: 2026-08-02 标准 `VACUUM` 的目标不只是“释放空间”:它让 dead row versions 可复用、维护 planner statistics 和 visibility map,并防止 transaction ID/multixact wraparound。多数系统应保持 autovacuum 开启。 ## 日常观测 [#日常观测] ```sql SELECT schemaname, relname, n_live_tup, n_dead_tup, last_vacuum, last_autovacuum, vacuum_count, autovacuum_count, last_analyze, last_autoanalyze FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 30; ``` 统计是估算且会重置,不能仅凭一个 `n_dead_tup` 阈值判断膨胀。结合表大小、更新速率、查询延迟、autovacuum 日志和趋势。 查看正在运行的 vacuum: ```sql SELECT pid, datname, relid::regclass AS relation, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, dead_tuple_bytes, num_dead_item_ids, indexes_total, indexes_processed FROM pg_stat_progress_vacuum; ``` 这些字段名对应 PostgreSQL 18;较早 major 的 progress view 列可能不同,跨版本监控应先核对目标版本目录。 ## 为什么没有触发或跟不上 [#为什么没有触发或跟不上] * 表很大,默认 scale factor 对应的变更行数过高; * worker、I/O 或维护内存不足; * 长事务、prepared transaction、复制槽或 standby snapshot 阻止回收; * vacuum 经常被冲突锁取消; * 写入峰值持续高于清理能力。 针对已验证的热点表覆盖参数,而不是先全局激进调整: ```sql ALTER TABLE app.events SET ( autovacuum_vacuum_scale_factor = 0.02, autovacuum_vacuum_threshold = 1000, autovacuum_analyze_scale_factor = 0.01 ); ``` 参数只是示例。根据表大小和每天变更量计算触发频率,并观察 I/O、WAL、延迟与实际完成时间。 ## 手工维护边界 [#手工维护边界] ```sql VACUUM (ANALYZE, VERBOSE) app.events; ``` 普通 `VACUUM` 主要让空间在关系内部复用,通常不会把文件缩回操作系统。`VACUUM FULL` 会重写整张表、需要额外磁盘并获取 `ACCESS EXCLUSIVE` 锁,不是日常清理命令。 先找出具体表、阶段、等待事件和资源瓶颈。关闭 autovacuum 会积累 dead tuples、陈旧统计和冻结风险;反 wraparound vacuum 即使表级设置关闭也可能运行。 完整原理见 [PostgreSQL 18 Routine Vacuuming](https://www.postgresql.org/docs/18/routine-vacuuming.html)。 --- # 备份、恢复与 PITR Canonical URL: https://pg.edu.rich/docs/operations/backup-recovery Last reviewed: 2026-08-02 ## 选择工具 [#选择工具] | 需求 | 工具/方式 | 关键边界 | | ----------- | ------------------------------------- | ----------------------- | | 单库、可移植、选择对象 | `pg_dump` / `pg_restore` | 不包含集群级角色与 tablespace 定义 | | 全集群逻辑对象 | `pg_dumpall --globals-only` 配合各库 dump | 大库恢复慢,需重建索引 | | 整实例快速恢复 | `pg_basebackup` 或成熟备份工具 | 版本和平台约束更强 | | 恢复到某一时间点 | 物理基准备份 + 连续 WAL 归档 | 必须持续验证 WAL 完整性 | ### pgBackRest、WAL-G 与 pg\_dump 怎么选 [#pgbackrestwal-g-与-pg_dump-怎么选] | 方案 | 更适合 | 不足以单独证明 | | -------------------------------------------------------- | ----------------------------------------------------------------- | ------------------------ | | [`pgBackRest`](https://github.com/pgbackrest/pgbackrest) | 自托管实例的 full/differential/incremental、并行备份、多 repository、WAL 与 PITR | 目标 RTO 已达标,密钥和所有 WAL 都可用 | | [`WAL-G`](https://github.com/wal-g/wal-g) | 对象存储导向的物理备份与 WAL 工作流 | repository 保留、删除保护和恢复正确 | | `pg_dump` / `pg_restore` | 逻辑迁移、选择对象、小规模恢复与跨版本导出 | 连续时间点恢复或整实例低 RTO | | 云平台备份 | 降低基础设施维护量 | 跨账户、跨区域、平台外恢复和全部扩展可恢复 | 不要机械套用固定的每日/每周频率。由 RPO、WAL 生成量、恢复带宽、保留策略和实测 RTO 反推 backup cadence,并保留至少一份独立于主数据库权限边界的副本。 ## 逻辑备份 [#逻辑备份] 自定义格式支持并行恢复与选择对象: ```bash pg_dump \ --format=custom \ --file=commerce-20260802.dump \ --dbname='postgresql://backup@db.example/commerce' pg_restore --list commerce-20260802.dump createdb commerce_restore_test pg_restore \ --dbname=commerce_restore_test \ --jobs=4 \ --exit-on-error \ commerce-20260802.dump ``` `pg_dump` 在导出期间提供一致快照,但只能备份一个 database。角色等全局对象另行备份: ```bash pg_dumpall --globals-only > globals-20260802.sql ``` 不要把包含密码哈希的 globals 文件放进普通制品库。 ## 物理备份与 PITR [#物理备份与-pitr] PITR 需要:可用的基准备份、从基准备份起连续完整的 WAL、正确的恢复配置,以及时间线管理。只保存 WAL 不够;只做 base backup 也无法恢复到任意时间点。 归档命令必须只在安全复制成功后返回 0,并避免覆盖已有文件。对象存储通常需要成熟备份工具管理并发、校验、保留和加密,而不是一条未经监控的 shell 命令。 持续告警 archive failure、缺失 WAL、repository 容量和最近一次可恢复时间。删除旧备份前,让工具按依赖关系计算保留链;不要只按文件日期手工删除。 ## 恢复演练 [#恢复演练] 每次演练记录:备份 ID、起止时间、恢复目标、数据库版本、所需密钥、实际 RTO、可恢复到的最新事务时间、校验查询和异常。 验证至少包括: ```sql SELECT count(*) FROM critical_table; SELECT min(created_at), max(created_at) FROM critical_table; SELECT conname, convalidated FROM pg_constraint WHERE NOT convalidated; SELECT indexrelid::regclass, indisvalid FROM pg_index WHERE NOT indisvalid; ``` 再运行应用层只读冒烟测试。行数相同不证明业务关系和权限正确。 复制会快速复制误删、错误更新和逻辑损坏。备份需要独立保留、删除保护、校验和恢复演练。 --- # 生产运维入口 Canonical URL: https://pg.edu.rich/docs/operations Last reviewed: 2026-08-02 ## 先定义目标 [#先定义目标] | 目标 | 要回答的问题 | | --- | ----------------------- | | RPO | 最多允许丢失多少数据? | | RTO | 故障后多久必须恢复服务? | | 容量 | 峰值连接、数据增长、WAL 与备份增长是多少? | | 可用性 | 哪些故障自动切换,哪些必须人工判断? | | 安全 | 谁能连接、读哪些数据、做哪些变更? | 没有目标的“高可用”和“做了备份”不可验证。 ## 每日最小检查 [#每日最小检查] ```sql SELECT now(), version(); SELECT state, count(*) FROM pg_stat_activity GROUP BY state ORDER BY state; SELECT datname, age(datfrozenxid) FROM pg_database ORDER BY age(datfrozenxid) DESC; SELECT num_timed, num_requested, num_done, buffers_written, write_time, sync_time FROM pg_stat_checkpointer; SELECT buffers_clean, maxwritten_clean, buffers_alloc FROM pg_stat_bgwriter; ``` PostgreSQL 17 起,检查点统计位于 `pg_stat_checkpointer`,后台写进程统计仍在 `pg_stat_bgwriter`。字段定义见 [PostgreSQL 18 累积统计视图](https://www.postgresql.org/docs/18/monitoring-stats.html#MONITORING-PG-STAT-CHECKPOINTER-VIEW)。 还应监控磁盘空间、WAL 生成/归档、复制 lag、备份状态、事务时长、锁等待、查询延迟、autovacuum 活动和连接池饱和度。阈值必须来自本系统基线。 ## 变更纪律 [#变更纪律] 1. 在类似规模数据上测量锁与耗时。 2. 写明回退路径和不可逆点。 3. 设置 `lock_timeout`,避免迁移无限等待后突然获取大锁。 4. 观察执行期间的锁、WAL、复制延迟和错误率。 5. 用查询或业务指标验证结果。 生产 DDL 不是“执行成功就结束”,而是一个可观察、可中断、可验证的发布。 --- # PostgreSQL 监控:SQL、指标与日志 Canonical URL: https://pg.edu.rich/docs/operations/monitoring-logging Last reviewed: 2026-08-02 PostgreSQL 可观测性至少需要三层证据:**SQL 统计解释资源花在哪里,指标说明系统何时偏离基线,日志保留错误与事件上下文**。只装一个 dashboard 不能替代这三层。 ## 1. 用 pg\_stat\_statements 找工作负载热点 [#1-用-pg_stat_statements-找工作负载热点] `pg_stat_statements` 是 PostgreSQL 官方扩展。它需要加入 `shared_preload_libraries`,通常要重启实例,然后在需要统计的 database 中创建扩展: ```ini shared_preload_libraries = 'pg_stat_statements' compute_query_id = auto ``` ```sql CREATE EXTENSION IF NOT EXISTS pg_stat_statements; SELECT queryid, calls, total_exec_time, mean_exec_time, rows, shared_blks_hit, shared_blks_read, left(query, 160) AS query FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 20; ``` 按总耗时、平均耗时、调用次数、返回行数和 I/O 分别看排行;单次最慢与累计消耗最大不是同一个问题。统计会被重置,部署、故障和参数变更时应记录采样窗口。字段定义以 [pg\_stat\_statements 官方文档](https://www.postgresql.org/docs/current/pgstatstatements.html) 为准。 扩展会规范化常量,但日志、DDL、动态 SQL 和应用注释仍可能泄露标识符或业务数据。限制统计视图与日志读取权限,并为采集、保留和脱敏设定规则。 ## 2. 使用 JSON 日志保留事件上下文 [#2-使用-json-日志保留事件上下文] `jsonlog` 便于可靠解析时间、SQLSTATE、backend、database、用户、application name 和错误上下文: ```ini logging_collector = on log_destination = 'jsonlog' log_min_duration_statement = '500ms' # 示例值,应按负载基线调整 log_lock_waits = on deadlock_timeout = '1s' ``` 不要把示例阈值直接复制到所有环境。过低会产生大量 I/O 与敏感查询文本,过高会漏掉高频中等耗时 SQL。优先用 `pg_stat_statements` 发现累计热点,用日志解释错误、锁等待、检查点、autovacuum 和特定慢请求。参数语义见 [Error Reporting and Logging](https://www.postgresql.org/docs/current/runtime-config-logging.html)。 [pgBadger](https://github.com/darold/pgbadger) 可以分析 PostgreSQL 原生日志与 `jsonlog`,生成查询、连接、错误、锁、检查点和 autovacuum 报告。先确保日志格式稳定、轮转可靠、时区一致,再把它加入离线分析流程。 ## 3. 指标、Prometheus 与 Grafana [#3-指标prometheus-与-grafana] [postgres\_exporter](https://github.com/prometheus-community/postgres_exporter) 适合已有 Prometheus/Grafana 的团队。采集角色优先使用 `pg_monitor` 或必要的只读统计权限,不要给 exporter 超级用户: ```sql CREATE ROLE metrics LOGIN; GRANT pg_monitor TO metrics; ``` 在目标版本上核对 collector 和权限。其 multi-target 模式仍被上游标为 Beta,自定义 `extend.query-path` 已 deprecated;新采集需求应优先使用内置 collector 或单独的通用 SQL exporter,而不是积累不可维护的查询文件。 ### 最小信号集 [#最小信号集] | 领域 | 信号 | 需要一起看的上下文 | | ------ | ---------------------------------------- | ------------------------ | | 连接 | 使用量、等待、连接池队列 | pool mode、应用实例数、保留连接 | | 查询 | latency、calls、rows、I/O | deploy、plan 变化、参数分布 | | 事务 | 长事务、idle in transaction、冲突 | owner、重试能力、vacuum 影响 | | 锁 | 等待时长、阻塞链、deadlock | DDL、批任务、业务事务 | | WAL/复制 | 生成速率、archive failure、lag、slot retention | RPO、网络、磁盘余量 | | 维护 | dead tuples、freeze age、vacuum/analyze 进度 | 表写入率、autovacuum 参数 | | 存储 | 数据/WAL/临时文件增长、I/O latency | 容量预测、checkpoint、查询 spill | | 恢复 | 最近成功备份、可恢复时间、实测 RTO | repository、密钥、恢复演练 | 阈值应来自正常时段和峰值时段的基线,告警应指向可执行的诊断路径。复制 lag 的字节数、时间和 replay 状态含义不同,不能只设一个全局阈值。 ## 工具采用顺序 [#工具采用顺序] 1. 所有生产实例先启用并治理 `pg_stat_statements`。 2. 输出可解析日志,并把 SQLSTATE、锁等待、归档失败和 autovacuum 纳入采集。 3. 已有 Prometheus 时接入 postgres\_exporter 与 PostgreSQL 专用 dashboard。 4. 需要日志趋势报告时加入 pgBadger;管理多实例可评估 [pgwatch](https://github.com/cybertec-postgresql/pgwatch)。 5. 深度 workload 分析可评估 [PoWA](https://github.com/powa-team/powa);临时排障可使用 [pg\_activity](https://github.com/dalibo/pg_activity)。 工具越多不等于盲区越少。先统一 instance、database、role、application、query ID、时间窗口和变更事件这些关联维度。 --- # PostgreSQL 生产工具栈与高可用 Canonical URL: https://pg.edu.rich/docs/operations/production-stack Last reviewed: 2026-08-02 生产 PostgreSQL 的优先级通常是:**能够恢复 → 不耗尽连接 → 看得见问题 → 安全地变更 → 再自动故障切换**。高可用不能替代备份,副本也不能修复已经复制过去的误删。 截至 **2026-08-02**,PostgreSQL 18.4 是最新稳定 major 18 的当前 minor;14–18 仍处于官方支持期。生产实例应运行其所在 major 的当前 minor,而不是只因为 18 最新就强制跨 major 升级。版本状态见 [PostgreSQL versioning policy](https://www.postgresql.org/support/versioning/) 与 [18.4 release notes](https://www.postgresql.org/docs/current/release-18-4.html)。 ## 最小生产基线 [#最小生产基线] | 层 | 最先回答的问题 | 常见选择 | | ---- | -------------------------- | ------------------------------------ | | 数据库 | minor 更新、角色、TLS、参数、扩展如何管理? | PostgreSQL 官方包或经过验证的镜像 | | 连接 | 峰值应用并发会不会耗尽 backend? | 应用连接池,必要时 PgBouncer | | 恢复 | RPO/RTO 是多少,能否从平台外恢复? | pgBackRest、WAL-G 或云平台备份 + 独立副本 | | 可观测性 | 哪条 SQL、哪个等待事件、哪段日志解释故障? | `pg_stat_statements`、JSON 日志、指标采集 | | 变更 | DDL 锁、回填、回滚和兼容窗口如何验证? | expand-and-contract、迁移检查、真实 PG 测试 | | 可用性 | 独立故障域、仲裁和切换后数据边界是什么? | 托管 HA、Patroni、CloudNativePG 或 Pigsty | ## PgBouncer:不要默认选择 transaction pooling [#pgbouncer不要默认选择-transaction-pooling] [PgBouncer](https://www.pgbouncer.org/) 把大量客户端连接复用到较少的 PostgreSQL server connection。不要通过持续增大 `max_connections` 代替容量设计;每个 backend 都会占用内存和调度资源,还要给迁移、监控、备份、管理与复制保留连接。 | 模式 | server connection 归还时间 | 适用边界 | | ------------- | ---------------------- | --------------------- | | `session` | 客户端断开 | 兼容性最高,适合依赖会话状态的应用 | | `transaction` | 事务结束 | Web/API 常用,但必须验证会话级特性 | | `statement` | 每条语句结束 | 不允许多语句事务,只适合非常受控的负载 | transaction pooling 下,SQL 级 `PREPARE`、会话 advisory lock、`LISTEN`、带 `WITH HOLD` 的 cursor,以及许多依赖会话状态的做法不可用或受限。协议级 prepared statement 需要正确配置 `max_prepared_statements` 并验证驱动行为。完整矩阵见 [PgBouncer feature map](https://www.pgbouncer.org/features.html)。 上线前至少验证:认证与 TLS、prepared statements、临时表、迁移工具、连接 reset、failover、事务重试,以及 ORM 是否把状态留在 session。 ## pgBackRest、WAL-G 与云平台备份 [#pgbackrestwal-g-与云平台备份] [pgBackRest](https://github.com/pgbackrest/pgbackrest) 支持 full/differential/incremental backup、并行传输、多 repository、WAL archive 与 PITR,适合自托管 PostgreSQL 的完整恢复链路。[WAL-G](https://github.com/wal-g/wal-g) 更偏对象存储工作流。二者都不能通过“安装完成”证明可恢复。 备份周期应由 RPO、WAL 生成量、恢复带宽、保留要求和实测 RTO 推导,而不是机械套用“每周全量、每日增量”。必须持续检查 archive gap、对象删除保护、加密密钥、跨账户或跨主机副本,并定期恢复到临时实例。 `pg_dump` 仍适合逻辑迁移、选择对象和小规模恢复,但它不能单独提供连续时间点恢复。详见 [备份、恢复与 PITR](/docs/operations/backup-recovery)。 ## Patroni、CloudNativePG 与 Pigsty 怎么选 [#patronicloudnativepg-与-pigsty-怎么选] | 环境 | 候选方案 | 采用前提 | | ---------------- | --------------------------------------------- | -------------------------------- | | 托管云数据库 | 服务商的跨可用区 HA | 核对区域、故障切换、PITR、扩展与平台外恢复限制 | | 独立 VM / 裸机 | [Patroni](https://github.com/patroni/patroni) | 多个独立故障域、可靠 DCS、网络与存储运维能力 | | 已有 Kubernetes 平台 | [CloudNativePG](https://cloudnative-pg.io/) | 团队已能运维 K8s、存储、网络和 Operator 升级 | | 多集群自托管平台 | [Pigsty](https://github.com/pgsty/pigsty) | 接受 Ansible/VM 运维模型,并验证其集成组件与升级路径 | CloudNativePG 的对象存储备份当前应评估 [Barman Cloud Plugin](https://cloudnative-pg.io/plugin-barman-cloud/docs/intro/),不要照搬已弃用的内置 object-store 配置。不要仅为了一个 PostgreSQL 实例引入 Kubernetes。 它们会同时受到主机断电、内核故障、存储损坏和网络中断影响。自动选主只在节点、存储和仲裁边界真实独立时改善可用性。 ## 分阶段采用 [#分阶段采用] ### 生产基线 [#生产基线] * 当前 minor、角色分离、TLS 与受控扩展; * 连接预算,必要时部署并验证 PgBouncer; * 独立保留的备份、连续 WAL/PITR 与恢复演练; * SQL、指标、日志三层可观测性; * 迁移前锁测试、超时、回退路径和业务验证。 ### 条件采用 [#条件采用] * 只有存在独立故障域和明确 RTO 时,才引入自动故障切换; * 只有已有成熟 Kubernetes 运维时,才优先 CloudNativePG; * 只有管理多个自托管集群的收益覆盖平台复杂度时,才引入 Pigsty; * 只有真实工作负载需要时,才安装 pgvector、PostGIS、TimescaleDB 等扩展。 ### 实验通道 [#实验通道] PostgreSQL 19 Beta、较新的扩展和存储引擎应进入可丢弃的兼容性环境,而不是生产默认。将稳定版本测试与下一 major 测试拆成两条 CI 通道,见 [安全迁移与零停机 Schema 变更](/docs/operations/safe-migrations)。 --- # 复制、故障切换与升级 Canonical URL: https://pg.edu.rich/docs/operations/replication-upgrades Last reviewed: 2026-08-02 ## 物理与逻辑复制 [#物理与逻辑复制] | 维度 | 物理流复制 | 逻辑复制 | | ---- | ---------------------- | ------------------- | | 单位 | WAL/实例 | 表级变更 | | 目标 | 同一大版本体系的 standby、HA、只读 | 选择表、跨大版本迁移、数据分发 | | DDL | 物理同步 | 通常需要另行同步 schema | | 序列 | 物理同步 | 需单独处理序列状态 | | 写入冲突 | standby 不写 | subscriber 本地写入可能冲突 | 物理 standby 的基本观测: ```sql -- primary SELECT application_name, state, sync_state, sent_lsn, write_lsn, flush_lsn, replay_lsn FROM pg_stat_replication; -- standby SELECT pg_is_in_recovery(), pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn(), now() - pg_last_xact_replay_timestamp() AS replay_delay; ``` 没有新事务时,时间型 replay delay 可能为空或看起来很大;同时看 LSN、WAL 速率和业务健康。 ## 复制槽 [#复制槽] 复制槽可防止所需 WAL 被过早删除,但消费者停止时会持续占用磁盘。为 slot lag 和 `pg_wal` 空间设置告警与容量上限;删除槽前确认没有消费者依赖。 ```sql SELECT slot_name, slot_type, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained FROM pg_replication_slots; ``` ## 故障切换不是单条命令 [#故障切换不是单条命令] 切换流程要覆盖:确认 primary 确实不可用、评估未同步 WAL、提升目标节点、让旧 primary 无法继续接受写入(fencing)、更新路由、验证写入与后台任务、重建冗余。缺少 fencing 可能产生双主分叉。 ## 升级路径 [#升级路径] * **小版本**:同一 major 内只包含修复;通常更换二进制并重启,但仍要阅读 release notes。 * **大版本**:需要 `pg_upgrade`、逻辑 dump/restore 或逻辑复制迁移;数据目录不向前兼容。 * 可以跨过中间 major 直接升级,但应阅读所有中间版本 release notes,并验证扩展支持。 ### 大版本切换清单 [#大版本切换清单] 1. 清点扩展、collation、数据类型、驱动与复制拓扑。 2. 在恢复出的生产副本上演练升级,统计停机、磁盘与 `ANALYZE` 时间。 3. 跑应用测试、关键查询计划对比和数据校验。 4. 冻结或双写期间明确 source of truth。 5. 切换前确认复制追平、长事务清空、回退窗口仍有效。 6. 切换后重建统计、检查 invalid objects、错误率、性能与备份。 如果目标是当前正在测试的 major,请使用 [PostgreSQL 19:新功能与 18 升级 19 指南](/docs/postgresql-19) 核对 Beta 状态、兼容性变化与 `pg_upgrade --check` 清单。 PostgreSQL 每个 major 通常支持 5 年。新系统使用受支持版本的最新 minor;截至 2026-08,18、17、16、15、14 受支持,14 将在 2026-11 结束支持。详见 [版本策略](/docs/reference/version-policy)。 --- # PostgreSQL 安全迁移与零停机 Schema 变更 Canonical URL: https://pg.edu.rich/docs/operations/safe-migrations Last reviewed: 2026-08-02 零停机不是某条 DDL 的属性,而是**旧应用与新应用能否在迁移窗口内同时工作**。安全迁移需要兼容阶段、锁预算、真实数据规模测试、可观察执行和明确回退点。 ## 默认采用 expand-and-contract [#默认采用-expand-and-contract] 以重命名或替换一个高流量字段为例: 1. **Expand**:添加新字段或新表,不删除旧结构;尽量使用短元数据操作。 2. **Dual compatible**:应用能读取新旧结构,并在必要时双写;写入必须幂等。 3. **Backfill**:按主键范围或时间窗口小批回填,限制事务时长、WAL 与 replica lag。 4. **Switch**:先切读路径,再停止旧写入;用业务指标和校验查询确认。 5. **Contract**:经过一个可回退发布窗口后,才删除旧结构。 直接把“加列、回填、设 `NOT NULL`、删旧列”放进一个长事务,通常会扩大锁、WAL、rollback 和复制延迟风险。 ## 给锁等待设上限 [#给锁等待设上限] ```sql BEGIN; SET LOCAL lock_timeout = '2s'; SET LOCAL statement_timeout = '15min'; ALTER TABLE app.orders ADD COLUMN IF NOT EXISTS fulfillment_state text; COMMIT; ``` 示例超时不是通用默认值。`lock_timeout` 防止迁移长时间排队后在不可控时刻获得强锁;`statement_timeout` 限制执行时间。失败后应退出并调查 blocker,而不是无限重试。 添加约束时可把扫描与短锁阶段拆开: ```sql ALTER TABLE app.orders ADD CONSTRAINT orders_total_nonnegative CHECK (total_cents >= 0) NOT VALID; ALTER TABLE app.orders VALIDATE CONSTRAINT orders_total_nonnegative; ``` 先在目标 PostgreSQL 版本和代表性数据上检查具体 DDL 的锁级别。`CREATE INDEX CONCURRENTLY` 也会消耗 I/O、WAL 和更长时间,并需要检查失败后留下的 invalid index。 ## 推荐 CI 流水线 [#推荐-ci-流水线] ```text Schema / reviewed SQL ↓ Migration generation ↓ Squawk static checks ↓ Disposable PostgreSQL 18.4 ↓ Apply every migration from an empty and upgraded state ↓ pgTAP + application integration + RLS negative tests ↓ PostgreSQL 19 Beta compatibility lane ↓ Representative-data rehearsal → staging → production ``` * [Squawk](https://github.com/sbdchd/squawk) 检查常见危险迁移,例如非并发索引、未使用 `NOT VALID` 的约束和一些锁风险;它不是零停机证明。 * [Testcontainers for Node.js](https://github.com/testcontainers/testcontainers-node) 在 CI 中启动真实 PostgreSQL,适合验证事务、锁、RLS、JSONB、扩展与驱动行为。 * [pgTAP](https://github.com/theory/pgtap) 在数据库内部测试函数、触发器、约束和策略。 如果使用 Drizzle ORM,可让 Drizzle Kit 生成普通 schema 变更,再对生成 SQL 进行 Squawk 与人工审核。复杂 index、policy、function、extension 和 PostgreSQL 19 新语法可以使用受审查的原生 SQL;ORM 无法表达不代表数据库不应该使用。 ## 测试升级路径,而不只测试空库 [#测试升级路径而不只测试空库] CI 至少需要两种数据库状态: | 起点 | 能发现的问题 | | ------------------------------ | ---------------- | | 空数据库执行全部 migration | 顺序、依赖、语法和初始化问题 | | 生产版本 schema/脱敏数据执行增量 migration | 锁、回填、旧数据、约束与性能问题 | 再将测试拆成两条版本通道: * **生产门禁**:当前生产 major/minor,例如 PostgreSQL 18.4,失败时阻止发布; * **前瞻兼容**:PostgreSQL 19 Beta 2,可允许失败但必须归类、跟踪和在 GA 前清零。 不要让 Beta 测试替代稳定版本门禁。版本状态见 [PostgreSQL 19 专题](/docs/postgresql-19)。 ## RLS 与安全对象必须做反向测试 [#rls-与安全对象必须做反向测试] 迁移成功不代表权限正确。为每个 tenant 和 role 验证:允许的 `SELECT/INSERT/UPDATE/DELETE` 成功,不允许的跨租户读写失败;应用运行角色不是表 owner,必要时启用 `FORCE ROW LEVEL SECURITY`。详见 [安全基线](/docs/operations/security)。 删除列、不可逆回填、类型收窄和外部副作用可能无法安全逆转。每次发布应写明最后可回退时点、旧应用能否读取新 schema,以及 forward fix 的触发条件。 ## 何时采用更重的工具 [#何时采用更重的工具] | 工具 | 适用场景 | 采用前先验证 | | ------------------------------------------------------------------------- | --------------------------- | -------------------- | | [pgroll](https://github.com/xataio/pgroll) | 高频、兼容窗口明确的零停机 schema change | 支持的 DDL、代理/连接方式、回滚语义 | | [Bytebase](https://github.com/bytebase/bytebase) | 多团队审批、SQL review、环境和审计治理 | 权限边界、部署模型、现有 CI 集成 | | [Database Lab Engine](https://github.com/postgres-ai/database-lab-engine) | 大型数据库的快速 clone 与迁移演练 | 存储、脱敏、clone 生命周期与成本 | 小团队先把 expand-and-contract、真实 PostgreSQL 测试、锁观察与恢复演练做好,再引入控制面。 --- # 安全基线 Canonical URL: https://pg.edu.rich/docs/operations/security Last reviewed: 2026-08-02 ## 分离角色 [#分离角色] ```sql CREATE ROLE app_owner NOLOGIN; CREATE ROLE app_runtime LOGIN; CREATE ROLE app_migrator LOGIN NOINHERIT; CREATE SCHEMA app AUTHORIZATION app_owner; GRANT app_owner TO app_migrator; GRANT CONNECT ON DATABASE commerce TO app_runtime, app_migrator; GRANT USAGE ON SCHEMA app TO app_runtime; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app TO app_runtime; ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_runtime; ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app GRANT USAGE, SELECT ON SEQUENCES TO app_runtime; ``` 运行时角色不拥有对象,迁移角色只在迁移期间 `SET ROLE app_owner`,所有者角色不登录。`ALTER DEFAULT PRIVILEGES` 只影响未来由指定创建者创建的对象,不会回补已有对象。 ## 认证与网络 [#认证与网络] * 只监听需要的接口,用防火墙/安全组限制来源。 * 远程连接要求 TLS,并验证服务端证书;高敏场景考虑客户端证书。 * 新密码认证使用 SCRAM,逐步淘汰 MD5 配置。 * `pg_hba.conf` 按具体网络、database、role 从窄到宽编排;修改后 reload 并测试允许与拒绝两条路径。 * 管理入口与应用入口分开,避免向公网暴露数据库端口。 ## search\_path 防护 [#search_path-防护] 不要信任可写 schema 中的同名对象解析。撤销 `public` 的默认创建权,并为安全敏感函数固定路径: ```sql REVOKE CREATE ON SCHEMA public FROM PUBLIC; CREATE FUNCTION app.current_tenant() RETURNS bigint LANGUAGE sql STABLE SECURITY DEFINER SET search_path = pg_catalog, app AS $$ SELECT current_setting('app.tenant_id')::bigint $$; REVOKE ALL ON FUNCTION app.current_tenant() FROM PUBLIC; GRANT EXECUTE ON FUNCTION app.current_tenant() TO app_runtime; ``` `SECURITY DEFINER` 函数以所有者权限运行,必须审计所有参数、对象限定名、search path 和执行权限。 ## 行级安全 RLS [#行级安全-rls] ```sql ALTER TABLE app.orders ENABLE ROW LEVEL SECURITY; ALTER TABLE app.orders FORCE ROW LEVEL SECURITY; CREATE POLICY tenant_orders ON app.orders USING (tenant_id = current_setting('app.tenant_id')::bigint) WITH CHECK (tenant_id = current_setting('app.tenant_id')::bigint); ``` RLS 启用后,没有适用策略时默认拒绝。超级用户、`BYPASSRLS` 角色以及通常的表所有者可绕过;`FORCE ROW LEVEL SECURITY` 让所有者在普通访问中也受策略约束。仍需普通对象权限。 管理员测试成功不能证明 RLS 有效。测试允许租户、其他租户、缺失 tenant context、插入与更新,并确认连接池每次借出/归还时正确设置和清除上下文。 ## Secret 与日志 [#secret-与日志] 凭据轮换、短期化并由 secret manager 分发。数据库日志避免记录绑定值和敏感 DDL;审计日志限制访问与保留期。`pg_stat_activity` 也可能显示 SQL 文本,读取监控视图的权限同样需要控制。 --- # PostgreSQL 连接错误排查 Canonical URL: https://pg.edu.rich/docs/reference/connection-errors Last reviewed: 2026-08-02 连接失败发生在 SQL 执行之前时,客户端不一定能得到 SQLSTATE。保留完整错误文本、时间、客户端版本和目标 host/port,但不要记录密码。 ## 固定诊断顺序 [#固定诊断顺序] ```text DNS 解析 → TCP 路由/防火墙/监听端口 → TLS 协商与证书身份 → pg_hba.conf 匹配 → 用户认证 → database 与 CONNECT 权限 → 连接数/池容量 → 会话初始化参数 ``` 跳过前一层直接重置密码或放宽权限,通常会掩盖真实问题。 ## 高频错误 [#高频错误] | 错误 | 含义 | 验证 | | -------------------------------- | ---------------------------------- | ------------------------------------- | | `could not translate host name` | DNS/主机名无法解析 | `getent hosts`、`nslookup`,核对拼写和私网 DNS | | `connection refused` | 目标地址没有接受该端口 | 服务状态、`listen_addresses`、端口和容器映射 | | `connection timed out` | 网络路径或防火墙丢弃 | 从同一应用环境测试 TCP,不从个人电脑代替 | | `no pg_hba.conf entry` | 没有匹配来源/database/user/TLS 的 HBA 规则 | 查看服务端日志和规则顺序;修改后 reload | | `password authentication failed` | 凭据或认证方式不匹配,常见 SQLSTATE `28P01` | 确认目标实例和 user,安全轮换密码 | | `database ... does not exist` | 目标实例中没有该 database,SQLSTATE `3D000` | 连接 `postgres` 后查询 `pg_database` | | `too many connections` | 实例/角色/数据库连接上限耗尽,SQLSTATE `53300` | `pg_stat_activity`、连接池与保留管理连接 | | `certificate verify failed` | CA、主机名、有效期或证书链错误 | 检查 `sslmode`、URI host、CA 和平台轮换通知 | ## 客户端验证 [#客户端验证] ```bash psql --version psql -X "postgresql://app_reader@db.example.com:5432/commerce?sslmode=verify-full" ``` 连接成功后立即运行: ```sql \conninfo SELECT current_database(), current_user, inet_server_addr(), inet_server_port(), current_setting('server_version'); ``` ## 服务端最小检查 [#服务端最小检查] ```sql SELECT datname, datallowconn, datconnlimit FROM pg_database ORDER BY datname; SELECT usename, application_name, client_addr, state, count(*) FROM pg_stat_activity GROUP BY usename, application_name, client_addr, state ORDER BY count(*) DESC; ``` 需要操作系统权限时再检查监听 socket、防火墙和 PostgreSQL 日志。云数据库没有主机权限,应使用平台连接诊断、网络流日志和审计日志。 把 `pg_hba.conf` 改为 `trust` 会移除认证边界,并且不能证明原密码为何失败。应在受控渠道轮换凭据,核对匹配到的 HBA 规则和服务端日志。 成功连接的安全配置见 [`psql` 与 SSL](/docs/setup/psql-connection);SQL 执行错误见 [SQLSTATE 速查](/docs/reference/errors)。 --- # 编辑、事实核对与更正政策 Canonical URL: https://pg.edu.rich/docs/reference/editorial-policy Last reviewed: 2026-08-02 ## 内容责任 [#内容责任] PostgreSQL Field Guide 是独立社区知识库,与 PostgreSQL Global Development Group 及文中云厂商无隶属关系。本站提供学习路径、工程解释和可验证示例;规范行为最终以目标版本的 PostgreSQL 官方文档为准。 ## 来源优先级 [#来源优先级] 1. PostgreSQL 当前受支持版本的官方手册、release notes 与 versioning 页面。 2. 扩展的上游仓库和发行说明,例如 pgvector 官方仓库。 3. 云服务商针对具体产品、区域和引擎版本的官方文档。 4. 可复现的本地测试与公开技术标准。 社区文章可以帮助发现问题,但不会单独支撑版本、接口、安全或恢复结论。 ## 发布检查 [#发布检查] * SQL 名称、系统视图和参数先查目标版本文档,不凭记忆补接口。 * 可安全执行的示例尽量在 PostgreSQL 18 临时实例验证。 * 写入、锁表、恢复、权限与复制操作明确风险和前置条件。 * 中英文页面同路径发布;任一语言不得是空占位或机器直译草稿。 * 云产品能力记录核对日期,并提醒读者重新确认区域、SKU 与扩展版本。 * 页面通过类型检查、lint、生产构建、内部链接和关键 HTTP/SEO 检查。 ## AI 辅助披露 [#ai-辅助披露] AI 可以辅助资料整理、翻译初稿、示例审查和一致性检查,但不能作为事实来源。涉及数据库行为的结论必须回到官方资料或可复现实验;涉及业务口径、风险接受和生产变更的决定必须由人类负责。 ## 日期与更正 [#日期与更正] 页面底部的“最后更新”表示最近一次内容核对日期。发现错误时,应同时修正中英文页面、相关交叉链接和机器可读 Markdown,并在项目的内容核对记录中保留可追踪说明。 当前全站基线核对日期:**2026-08-02**。 --- # SQLSTATE 错误速查 Canonical URL: https://pg.edu.rich/docs/reference/errors Last reviewed: 2026-08-02 应用应分支处理 **SQLSTATE**,不要匹配可能随版本和语言变化的错误文本。 ## 高频状态码 [#高频状态码] | SQLSTATE | 名称 | 常见含义 | 稳妥动作 | | -------- | ----------------------------- | --------------------- | ------------------------------ | | `23505` | unique\_violation | 唯一键冲突 | 返回冲突或使用明确的 `ON CONFLICT` 语义 | | `23503` | foreign\_key\_violation | 引用不存在/仍被引用 | 修正操作顺序,不要临时禁用约束 | | `23502` | not\_null\_violation | 必填列缺失 | 修正输入或迁移顺序 | | `23514` | check\_violation | 违反 `CHECK` | 解释业务边界,修正值 | | `22P02` | invalid\_text\_representation | 类型转换失败 | 在应用边界校验并绑定正确类型 | | `40001` | serialization\_failure | 并发下无法保持隔离保证 | 回滚并重试整个事务 | | `40P01` | deadlock\_detected | 形成等待环 | 回滚整事务;统一锁顺序 | | `55P03` | lock\_not\_available | `NOWAIT`/lock timeout | 稍后重试或返回冲突 | | `57014` | query\_canceled | statement timeout 或取消 | 区分主动取消与超时,优化或缩小请求 | | `25P02` | in\_failed\_sql\_transaction | 当前事务此前已失败 | `ROLLBACK`;不要继续发业务 SQL | | `42501` | insufficient\_privilege | 对对象或动作无权限 | 修正 grant/owner;不要提升为 superuser | | `42P01` | undefined\_table | 表不存在或 search path 错 | 核对 database/schema/迁移版本 | | `42703` | undefined\_column | 列不存在 | 核对 schema 契约与部署版本 | | `53300` | too\_many\_connections | 连接槽耗尽 | 检查池配置、泄漏、保留管理连接 | | `57P03` | cannot\_connect\_now | 启动、恢复或关闭中 | 带上限退避,检查实例状态 | | `08006` | connection\_failure | 连接已失败 | 判断事务结果是否未知,再安全重试 | ## 事务失败后的规则 [#事务失败后的规则] 事务内任意语句失败后,通常进入 aborted 状态: ```text ERROR: current transaction is aborted... SQLSTATE: 25P02 ``` 必须 `ROLLBACK`,或回滚到失败前创建的 savepoint。不要继续发送语句期待自动恢复。 ## 重试分类 [#重试分类] * **可整事务重试**:`40001`、`40P01`;使用次数上限、指数退避和 jitter。 * **可能短暂重试**:`55P03`、`57P03`、部分 `08***`;先确认幂等和事务提交状态。 * **输入/模型错误,不应盲重试**:`22***`、`23***`、`42***`、`42501`。 * **资源问题**:`53300`、磁盘满、内存问题;重试会放大故障,先降载和修复容量。 ## 诊断上下文 [#诊断上下文] 记录 SQLSTATE、约束/表/列名、数据库与 schema、应用版本、迁移版本、事务 ID/请求 ID、参数类型(敏感值脱敏)和是否已提交。驱动通常提供结构化错误字段,应直接读取。 ## AI 工具的返回 [#ai-工具的返回] ```json { "ok": false, "sqlstate": "23505", "category": "constraint", "retryable": false, "constraint": "customers_email_unique", "message_safe": "A customer with this email already exists" } ``` 不要把原始数据库错误无过滤地返回终端用户;它可能泄露对象名、路径或数据片段。 --- # PostgreSQL 扩展与开源生态选型指南 Canonical URL: https://pg.edu.rich/docs/reference/extensions-ecosystem Last reviewed: 2026-08-02 PostgreSQL 扩展让类型、索引、planner hook、后台 worker 和存储能力进入数据库进程,也会进入备份、复制、故障恢复和 major upgrade 的关键路径。选型原则是:**没有明确工作负载和退出方案,就不要安装**。 ## 安装前的六项门禁 [#安装前的六项门禁] 1. 目标 PostgreSQL major、操作系统和 CPU 架构有明确支持与 package。 2. 许可证满足自托管、SaaS、分发和商业功能边界。 3. 备份、PITR、standby、逻辑复制和恢复环境能够加载相同版本。 4. `pg_upgrade`、extension update 和需要重建的 index 有演练路径。 5. 托管云的区域、SKU 与 allowlist 提供所需版本,不只提供同名扩展。 6. 有不依赖该扩展的导出或迁移策略,避免无意中锁定平台。 记录 `SELECT extname, extversion FROM pg_extension`,并把扩展版本与数据库版本一起进入部署清单和 AI 上下文。 先检查 [PostgreSQL 索引与存储访问方法](/docs/reference/index-access-methods) 中的原生 B-tree/GIN/GiST/SP-GiST/BRIN、全文检索、分区、FDW 与物化视图。只有原生能力无法满足已测量的 workload 时,再增加 extension。 ## 按工作负载选择 [#按工作负载选择] | 场景 | 常见候选 | 采用边界 | | -------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | SQL 统计 | [`pg_stat_statements`](https://www.postgresql.org/docs/current/pgstatstatements.html) | 官方 contrib,生产可观测性基线;治理查询文本权限 | | 向量检索 / RAG | [pgvector](https://github.com/pgvector/pgvector) | 用真实过滤条件测 recall、latency、内存与索引构建 | | 地理空间 | [PostGIS](https://postgis.net/) | GIS 标准选择;确认 extension 与数据格式升级路径 | | 时间序列 | [TimescaleDB](https://github.com/timescale/timescaledb) | 需要 hypertable/压缩/连续聚合时评估;逐项核对许可证 | | 分布式多租户 | [Citus](https://github.com/citusdata/citus) | 单机已被测量为瓶颈且 shard key 稳定后再引入 | | BM25 / 搜索 | [ParadeDB / pg\_search](https://github.com/paradedb/paradedb) | 核对许可证、索引恢复、复制与云支持 | | PostgreSQL 内 BM25 | [pg\_textsearch](https://github.com/timescale/pg_textsearch) | 上游目前声明 production ready;仍需按目标版本和语料独立验收 | | 嵌入式分析 / Parquet | [pg\_duckdb](https://github.com/duckdb/pg_duckdb) | 适合分析路径;验证事务边界、资源隔离和对象存储凭据 | | Iceberg columnstore mirror | [pg\_mooncake](https://github.com/Mooncake-Labs/pg_mooncake) | 通过 logical change capture 维护 columnstore mirror;验证一致性、对象存储、pg\_duckdb 依赖与恢复 | | 图查询 | [Apache AGE](https://github.com/apache/age) | 只有图模型与 Cypher 带来可测收益时采用 | “上游 production ready”是项目自己的状态声明,不是对你的 workload、SLA 或云平台的认证。 ## 维护与数据治理 [#维护与数据治理] | 工具 | 作用 | 不应误解为 | | ------------------------------------------------------------------------ | ---------------------------------- | --------------------- | | [HypoPG](https://github.com/HypoPG/hypopg) | 用 hypothetical index 评估 planner 选择 | 真实构建成本和生产收益证明 | | [pg\_repack](https://github.com/reorg/pg_repack) | 以较短排他锁窗口重组表和 index | 日常 autovacuum 的替代品 | | [pg\_partman](https://github.com/pgpartman/pg_partman) | 管理原生时间/序列分区生命周期 | 自动修复错误 partition key | | [pg\_cron](https://github.com/citusdata/pg_cron) | 在数据库内调度简单 SQL 工作 | 通用业务队列和复杂 workflow 引擎 | | [Greenmask](https://github.com/GreenmaskIO/greenmask) | 生成脱敏、子集化的测试数据 | 可以无审查复制生产敏感数据 | | [PostgreSQL Anonymizer](https://gitlab.com/dalibo/postgresql_anonymizer) | 声明式静态/动态掩码 | 自动满足全部合规要求 | 严重膨胀先找长事务、autovacuum、写入模式与 fillfactor 根因,再使用 pg\_repack。分区只解决能按 partition key 剪枝和管理的数据生命周期问题。 ## PostgreSQL 19 REPACK 与 pg\_repack 不是一回事 [#postgresql-19-repack-与-pg_repack-不是一回事] PostgreSQL 19 Beta 文档中的核心 [`REPACK`](https://www.postgresql.org/docs/19/sql-repack.html) 是新 SQL command,`REPACK (CONCURRENTLY)` 基于 logical decoding,并对主键/replica identity、unlogged/partitioned/system table、replication slot 和磁盘空间有约束。 第三方 **pg\_repack** 是独立 extension 与命令行工具,具有自己的兼容矩阵、安装包和操作边界。不要因为名称相近,就把 pg\_repack 的经验、监控或风险模型直接套到 PostgreSQL 19 核心 `REPACK`。 截至 2026-08-02,PostgreSQL 19 仍为 Beta 2。核心 REPACK 的语义和限制应以最终 GA 文档与自己的恢复副本演练为准。 ## AI、备份与升级清单 [#ai备份与升级清单] 向 AI/Agent 提供:`server_version_num`、`extname/extversion`、允许使用的 operator/index method、目标云限制和禁止语法。不要仅告诉模型“这是 PostgreSQL”。 每次扩展升级前完成: 1. 读取目标版本 release notes、SQL update script 和已知重建要求; 2. 从真实备份恢复到隔离环境; 3. 升级 PostgreSQL 与 extension,运行完整性、性能和 RLS 测试; 4. 重建要求的 index,并比较 plan、recall 或业务结果; 5. 重新生成备份并执行一次恢复,确认新版本链路成立。 Supabase、Neon、YugabyteDB、CockroachDB、Cloudberry、Gel 和 FerretDB 不应混进“扩展排行榜”:它们分别是平台、分支、独立数据库或协议转换层。分类见 [PostgreSQL 血缘与兼容数据库](/docs/reference/postgresql-compatible-databases)。 --- # PostgreSQL 索引与存储访问方法 Canonical URL: https://pg.edu.rich/docs/reference/index-access-methods Last reviewed: 2026-08-02 PostgreSQL 不采用 MySQL 那种为普通表频繁选择 InnoDB/MyISAM 的使用模型。绝大多数表使用核心 **heap table access method**;索引通过独立的 index access method 和 operator class 决定支持哪些查询。 ## Table Access Method 不是日常调优开关 [#table-access-method-不是日常调优开关] PostgreSQL 提供 [Table Access Method API](https://www.postgresql.org/docs/current/tableam.html),允许扩展或定制构建实现新的表存储方式,但普通应用的默认仍是 `heap`: ```sql CREATE TABLE events ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, occurred_at timestamptz NOT NULL, payload jsonb NOT NULL ) USING heap; ``` 通常省略 `USING heap`。选择新 table access method 会进入 WAL、MVCC、VACUUM、backup、replication、extension 和 major upgrade 的关键路径,不能像切换 query hint 一样随意尝试。 查看当前实例暴露的 access method: ```sql SELECT amname, CASE amtype WHEN 't' THEN 'table' WHEN 'i' THEN 'index' ELSE amtype::text END AS access_method_type FROM pg_am ORDER BY amtype, amname; ``` ## 核心索引访问方法 [#核心索引访问方法] PostgreSQL 18 核心提供 B-tree、Hash、GiST、SP-GiST、GIN 和 BRIN;`bloom` 是随 PostgreSQL 提供但需要 `CREATE EXTENSION bloom` 的 module。官方边界见 [Index Types](https://www.postgresql.org/docs/current/indexes-types.html)。 | 类型 | 优先场景 | 重要边界 | | --------------- | --------------------------------- | ---------------------------------------------------------------------------------- | | B-tree | `=`、范围、排序、unique、前缀模式匹配 | 默认选择;复合列顺序与 operator class 决定可用查询 | | Hash | 单列等值比较 | 只支持 `=`;B-tree 通常更通用,采用前需有测量收益 | | GIN | JSONB、array、全文检索和多值内容 | 更新和构建成本较高;行为取决于 operator class | | GiST | range、几何、PostGIS、nearest-neighbor | 是可扩展框架,不是单一算法;必须匹配 operator/operator class | | SP-GiST | trie、quad-tree、k-d tree 等空间分区结构 | 适合具有可分区结构的数据;不是 GiST 的通用替换 | | BRIN | 与物理顺序高度相关的超大追加表 | 保存 block range 摘要;相关性差时会读取大量 heap block | | Bloom extension | 多列任意组合的等值过滤 | lossy、需要 recheck;不支持 range、unique 或搜索 `NULL`;自带 operator class 仅覆盖 `int4` 与 `text` | GIN、GiST、SP-GiST 和 BRIN 是框架。真正决定支持哪些 operator、排序和数据类型的是 operator class。看到“使用 GIN”仍不足以复现一个索引设计。 ## 常见工作负载映射 [#常见工作负载映射] ```text 等值 / 范围 / 排序 / unique → B-tree JSONB contains / array member → GIN PostgreSQL FTS → GIN(通常) range / GIS / nearest neighbor → GiST 或匹配的 SP-GiST 超大、按时间物理追加 → BRIN 向量 ANN → pgvector HNSW / IVFFlat ``` HNSW 与 IVFFlat 来自 [pgvector](https://github.com/pgvector/pgvector),不是 PostgreSQL 核心 index method。它们需要单独验证 recall、filter、memory、build time、WAL、replica lag 与 extension upgrade。 PostgreSQL 内置全文检索支持 parser、dictionary、ranking、highlight 和 GIN/GiST index。内置配置不自动解决所有语言的分词;例如中文通常需要额外 tokenizer/extension 或应用侧预处理,不能只创建一个 GIN 就宣称搜索质量成立。 ## 创建前先匹配查询 [#创建前先匹配查询] ```sql -- 普通业务过滤与排序 CREATE INDEX CONCURRENTLY orders_customer_time_idx ON orders (customer_id, placed_at DESC); -- JSONB 包含查询:payload @> '{"status":"paid"}' CREATE INDEX CONCURRENTLY events_payload_gin_idx ON events USING gin (payload jsonb_path_ops); -- 时间与物理写入顺序高度相关的大表 CREATE INDEX CONCURRENTLY events_time_brin_idx ON events USING brin (occurred_at); ``` `jsonb_path_ops` 更专注于 `@>`、`@?`、`@@` 等路径/包含查询,并不支持默认 `jsonb_ops` 的全部 operator。索引 DDL 必须从真实 query shape 反推。 创建后记录 plan 与尺寸: ```sql SELECT indexrelname, idx_scan, pg_size_pretty(pg_relation_size(indexrelid)) AS index_size FROM pg_stat_user_indexes WHERE relname = 'events' ORDER BY pg_relation_size(indexrelid) DESC; ``` 再使用 `EXPLAIN (ANALYZE, BUFFERS)` 比较实际行数、heap block、recheck、排序与写入代价。完整步骤见 [索引与 EXPLAIN](/docs/core/indexes-explain)。 ## 原生能力优先 [#原生能力优先] | 需求 | 先验证 PostgreSQL 原生 | 仍不足时再评估 | | ------ | -------------------------------------------------- | --------------------------------- | | 模糊匹配 | FTS、`pg_trgm` contrib、表达式/GIN/GiST index | 外部搜索或 BM25 extension | | 任务互斥 | transaction、`FOR UPDATE SKIP LOCKED`、advisory lock | 专用队列与 workflow 系统 | | 时间生命周期 | 原生 partition、BRIN、scheduled cleanup | pg\_partman、TimescaleDB | | 跨库访问 | `postgres_fdw`、logical replication | CDC 平台或独立同步系统 | | 分析 | materialized view、partition、parallel query | pg\_duckdb、pg\_mooncake、warehouse | | 向量检索 | 没有核心 vector type/index | pgvector 或专用向量系统 | “原生优先”不是拒绝扩展,而是减少不必要的 binary、license、backup 和 upgrade 依赖。扩展候选见 [PostgreSQL 扩展生态选型](/docs/reference/extensions-ecosystem)。 --- # PostgreSQL 现场速查 Canonical URL: https://pg.edu.rich/docs/reference Last reviewed: 2026-08-02 ## psql [#psql] ```bash psql 'postgresql://user@host:5432/database?sslmode=verify-full' psql -X --set ON_ERROR_STOP=on --file migration.sql "$DATABASE_URL" ``` | 命令 | 作用 | | ---------------- | ------------ | | `\conninfo` | 当前连接信息 | | `\l` | database 列表 | | `\dn` | schema 列表 | | `\dt app.*` | 表列表 | | `\d+ app.orders` | 对象定义与存储信息 | | `\du` | 角色列表 | | `\dx` | 扩展列表 | | `\timing on` | 显示客户端观察的耗时 | | `\x auto` | 宽结果自动纵向显示 | | `\gdesc` | 描述查询结果列而不展示行 | | `\q` | 退出 | 脚本使用 `-X` 避免加载用户 `.psqlrc`,并用 `ON_ERROR_STOP` 在首个错误退出。 ## 当前上下文 [#当前上下文] ```sql SELECT version(), current_database(), current_user, session_user, current_schema(), current_setting('TimeZone') AS timezone, inet_server_addr(), inet_server_port(); ``` ## 对象大小 [#对象大小] ```sql SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) AS total, pg_size_pretty(pg_relation_size(relid)) AS heap, pg_size_pretty(pg_indexes_size(relid)) AS indexes FROM pg_catalog.pg_statio_user_tables ORDER BY pg_total_relation_size(relid) DESC LIMIT 20; ``` ## 活跃会话与长事务 [#活跃会话与长事务] ```sql SELECT pid, usename, application_name, state, now() - xact_start AS xact_age, wait_event_type, wait_event, left(query, 160) AS query FROM pg_stat_activity WHERE pid <> pg_backend_pid() ORDER BY xact_start NULLS LAST; ``` ## 谁阻塞谁 [#谁阻塞谁] ```sql SELECT blocked.pid AS blocked_pid, blocker.pid AS blocker_pid, now() - blocked.query_start AS blocked_for, left(blocked.query, 120) AS blocked_query, left(blocker.query, 120) AS blocker_query FROM pg_stat_activity AS blocked CROSS JOIN LATERAL unnest(pg_blocking_pids(blocked.pid)) AS b(pid) JOIN pg_stat_activity AS blocker ON blocker.pid = b.pid; ``` 不要看到 blocker 就立刻 `pg_terminate_backend`。先确认业务、事务内容、是否可重试和终止后影响。 ## 安全的会话设置 [#安全的会话设置] ```sql BEGIN; SET LOCAL statement_timeout = '10s'; SET LOCAL lock_timeout = '2s'; SET LOCAL search_path = app, pg_catalog; -- work COMMIT; ``` ## 诊断顺序 [#诊断顺序] 确认目标实例与角色 → 记录 SQLSTATE → 检查事务状态 → 检查等待事件/阻塞 → 获取查询计划与统计 → 在受控环境复现 → 修复后执行验证查询。 连接尚未建立时使用 [PostgreSQL 连接错误排查](/docs/reference/connection-errors);连接成功后的 SQL 错误使用 [错误与 SQLSTATE](/docs/reference/errors)。 扩展、维护工具和开源组件的升级边界见 [PostgreSQL 扩展与开源生态选型](/docs/reference/extensions-ecosystem)。 索引与存储概念见 [PostgreSQL 索引与存储访问方法](/docs/reference/index-access-methods);协议兼容、分支与 PostgreSQL 血缘见 [PostgreSQL 血缘与兼容数据库](/docs/reference/postgresql-compatible-databases)。 --- # PostgreSQL 血缘、分支与兼容数据库 Canonical URL: https://pg.edu.rich/docs/reference/postgresql-compatible-databases Last reviewed: 2026-08-02 “基于 PostgreSQL”“使用 PostgreSQL 协议”和“可以替换 PostgreSQL”是三个不同结论。兼容性至少有五层: ```text 驱动可以连接 → pgwire 消息可交换 → SQL / 类型 / 函数兼容 → catalog / extension / transaction 行为兼容 → backup / replication / upgrade / failure 语义兼容 ``` 越靠下,越需要真实迁移和故障测试。产品自称 PostgreSQL-compatible,通常只描述其中一部分。 ## PostgreSQL 为核心的开发平台 [#postgresql-为核心的开发平台] | 平台 | PostgreSQL 在哪里 | 平台增加了什么 | 不能直接假设 | | ------------------------------------------------------ | ------------------------------ | ----------------------------------------------------------- | ----------------------------------------------- | | [Supabase](https://github.com/supabase/supabase) | 每个项目运行 PostgreSQL | PostgREST、Auth、Realtime、Storage、Functions、Dashboard 与连接池 | 自托管与云平台功能/运维完全相同;浏览器 API 自动安全 | | [Neon](https://github.com/neondatabase/neon) | compute node 运行 PostgreSQL 查询层 | compute/storage separation、page server、branch、scale-to-zero | data directory、WAL、unlogged table、恢复与普通 PG 运维相同 | | [Nhost](https://github.com/nhost/nhost) | PostgreSQL 是 database | Hasura GraphQL、Auth、Storage、Functions | GraphQL permission 等同于全部数据库权限边界 | | [Prisma Postgres](https://www.prisma.io/docs/postgres) | 托管 PostgreSQL | PgBouncer、HTTP/edge driver、query cache、临时数据库和 Prisma 工具链 | operation 计费、pooling 和 extension 与任意自托管 PG 相同 | 这些平台适合继续使用普通 SQL、migration 和 `pg_dump` 思维,但仍要把平台的连接代理、休眠、备份、扩展 allowlist、API 权限和计费模型写进架构。 ## PostgreSQL 分支、查询层复用与新存储 [#postgresql-分支查询层复用与新存储] | 项目 | 实现路径 | 主要目标 | 迁移风险中心 | | --------------------------------------------------------------------------- | ------------------------------------------- | ----------------------------------------------- | ----------------------------------------------------- | | [YugabyteDB](https://github.com/yugabyte/yugabyte-db) | YSQL 复用 PostgreSQL query layer,底层是分布式 DocDB | 分布式事务、横向扩展、多区域 | extension、lock/isolation、catalog、DDL 与分布式成本模型 | | [PolarDB for PostgreSQL](https://github.com/polardb/PolarDB-for-PostgreSQL) | PostgreSQL 血缘的计算存储分离分支 | shared storage、一写多读、云原生架构 | 开源分支版本节奏、专用 storage/HA、与公有云版本差异 | | [Apache Cloudberry](https://github.com/apache/cloudberry) | Greenplum/PG 血缘的 MPP 数据库 | 数据仓库、大规模并行分析 | OLTP transaction、distribution key、SQL/extension 与运维工具 | | [IvorySQL](https://github.com/IvorySQL/IvorySQL) | 跟随 PostgreSQL 的 Oracle-compatible 分支 | PL/iSQL、Oracle syntax、package 与迁移 | compatibility mode、Oracle 语义、extension package 与上游同步 | | [openGauss](https://github.com/opengauss-mirror/openGauss-server) | PostgreSQL 血缘的独立数据库内核 | 企业部署、并行与自身生态 | 已长期独立演进,不能把当前 PostgreSQL 兼容性当作默认 | | [OrioleDB](https://github.com/orioledb/orioledb) | 面向 PostgreSQL 的新 storage engine,通常需要其支持的构建 | undo-based MVCC、copy-on-write/checkpoint、降低某些膨胀 | binary/build、WAL/backup、extension、major upgrade 与故障恢复 | 这里的“血缘”不等于 drop-in replacement。特别是分布式存储会改变 transaction retry、hot key、sequence、foreign key、lock 和一致性/延迟取舍。 ## 支持 PostgreSQL 客户端,但不是 PostgreSQL [#支持-postgresql-客户端但不是-postgresql] | 项目 | pgwire / PostgreSQL 的作用 | 实际定位 | | --------------------------------------------------------------------------------- | ---------------------------------------- | -------------------------------------------------------------- | | [CockroachDB](https://www.cockroachlabs.com/docs/stable/postgresql-compatibility) | 实现 pgwire 和大量 PostgreSQL syntax | 独立分布式 SQL 数据库;不等同于 PostgreSQL extension/catalog/transaction 行为 | | [Materialize](https://github.com/MaterializeInc/materialize) | PostgreSQL-compatible driver 可查询 view | 流式增量计算与实时数据层,不是通用 OLTP PostgreSQL | | [Gel](https://github.com/geldata/gel) | 底层使用 PostgreSQL 技术并提供 SQL interface/生态连接 | graph-relational database,主要数据模型和 query language 是 Gel/EdgeQL | 部分兼容数据库会报告 PostgreSQL 风格的 `server_version` 或提供相似 catalog。版本字符串只能帮助驱动选择协议路径,不能证明服务器运行同一 PostgreSQL 内核。 ## FerretDB 是反方向兼容 [#ferretdb-是反方向兼容] [FerretDB 2.x](https://github.com/FerretDB/FerretDB) 接收 MongoDB 5.0+ wire protocol,把请求转换为 SQL,并使用带 DocumentDB extension 的 PostgreSQL 作为 database engine: ```text MongoDB driver → FerretDB proxy → PostgreSQL + DocumentDB extension ``` 因此它不是“PostgreSQL client 连接一个 MongoDB-compatible server”,而是“MongoDB client 使用 PostgreSQL-backed document database”。验证重点是 MongoDB command/BSON 兼容矩阵、DocumentDB extension、索引、transaction、backup 与版本组合。 ## 迁移兼容性测试矩阵 [#迁移兼容性测试矩阵] | 层 | 必测内容 | 不能接受的替代证据 | | ------ | ------------------------------------------------------------ | ------------------------- | | 连接 | TLS、SCRAM、startup parameter、prepared statement、pooler | `psql` 能执行 `SELECT 1` | | Schema | type、identity/sequence、generated column、constraint、partition | ORM migration 只在空库成功 | | SQL | function/operator、JSONB、CTE/window、collation、全文 | 跑过简单 CRUD | | 事务 | isolation、retry、row lock、deadlock、advisory lock | 宣传页写“ACID” | | 扩展 | exact version、operator/index method、upgrade script | 扩展名称出现在 allowlist | | 运维 | backup/PITR、CDC、replication、catalog、monitoring | 有“backup”按钮 | | 故障 | node/zone failure、连接收敛、RPO/RTO、回滚 | vendor benchmark 或 SLA 数字 | 建议先运行应用测试和 migration,再恢复脱敏生产副本,最后做切换与回退演练。对于 CockroachDB/YugabyteDB 这类分布式数据库,还要主动制造 transaction conflict、hot partition 和节点故障。 ## 如何做选择 [#如何做选择] * 要标准 PostgreSQL 生态与最低迁移成本:优先社区 PostgreSQL 或明确运行 PostgreSQL 的托管服务。 * 要 BaaS:Supabase;要 GraphQL-first:Nhost;要 branch/scale-to-zero:Neon。 * 要多区域分布式 OLTP:把 YugabyteDB 与 CockroachDB 作为新数据库评估,不视为配置项。 * 要 MPP warehouse:评估 Cloudberry,不用 OLTP benchmark 推导分析性能。 * 要 Oracle migration:评估 IvorySQL,并保留 PostgreSQL mode 与 Oracle mode 的差异测试。 * 要实时增量 view:Materialize 是数据层候选,不是主 OLTP 数据库的透明替换。 云服务免费层见 [免费 PostgreSQL 云数据库选型](/docs/cloud/free-postgresql);真正的扩展选型见 [PostgreSQL 扩展生态](/docs/reference/extensions-ecosystem)。 --- # 版本与支持策略 Canonical URL: https://pg.edu.rich/docs/reference/version-policy Last reviewed: 2026-08-02 ## 版本号含义 [#版本号含义] 从 PostgreSQL 10 起,第一个数字是 major,例如 18;点后的数字是 minor,例如 18.4。major 大约每年发布一次并带来新功能;minor 只包含错误、安全和低风险修复。 minor 升级不需要 dump/restore,通常替换二进制并重启;仍应阅读该版本 release notes。major 之间的数据目录不兼容,需要 `pg_upgrade`、逻辑 dump/restore 或逻辑复制迁移。 ## 当前支持快照 [#当前支持快照] 截至 **2026-08-02**: | Major | 当前 minor | 支持状态 | 最终支持日期 | | ----- | -------: | --------- | ---------- | | 18 | 18.4 | 支持 | 2030-11-14 | | 17 | 17.10 | 支持 | 2029-11-08 | | 16 | 16.14 | 支持 | 2028-11-09 | | 15 | 15.18 | 支持 | 2027-11-11 | | 14 | 14.23 | 支持,即将 EOL | 2026-11-12 | 来源:[PostgreSQL 官方版本策略](https://www.postgresql.org/support/versioning/)。动态版本信息以该页为准。 ## 上游版本不等于发行版软件包版本 [#上游版本不等于发行版软件包版本] ### 各发行版默认 postgresql 软件包节选 PkgSeek 软件包快照;核对时间:2026-08-02 15:47:58 UTC。 | 发行版 | Release | 完整版本 | 仓库 | 关联公告 | |---|---|---|---|---:| | Alibaba Cloud Linux | 3 | 13.23-3.0.1.al8 | official / updates | 0 | | Alibaba Cloud Linux | 4 | 15.18-1.alnx4 | official / updates | 0 | | AlmaLinux | 10 | 16.14-1.el10_2 | official / AppStream | 0 | | AlmaLinux | 9 | 18.4-2.module_el9.8.0+280+5ad12178 | official / AppStream | 0 | | Arch | rolling | 18.4-3 | official / extra | 0 | | CentOS Stream | 10 | 16.14-1.el10 | official / AppStream | 0 | | CentOS Stream | 9 | 13.23-3.el9 | official / AppStream | 0 | | Debian | trixie | 17+278 | official / main | 3 | | deepin | 25.2 | 16+255 | official / main | 0 | | Fedora | 42 | 16.13-1.fc42 | official / updates | 0 | | Fedora | 43 | 18.3-2.fc43 | official / updates | 0 | | Fedora | 44 | 18.3-2.fc44 | official / updates | 0 | 来源:[PkgSeek 软件包查询](https://pkgseek.com/packages/postgresql)。发行版 revision 和回溯补丁属于完整版本身份。 发行版可能冻结 major,并在 `16.14-1.el10_2`、`18+290ubuntu1` 等完整版本号中记录打包 revision 和安全回溯。不能只截取开头的 `16` 或 `18` 判断漏洞状态;应使用发行版、release、repository、architecture 和完整 package version 共同定位,再核对厂商安全公告。 ## 新项目怎么选 [#新项目怎么选] 默认选择最新稳定 major 的最新 minor,除非驱动、扩展、托管平台或组织认证尚未支持。需要更保守时选择仍有充足支持窗口、且已被自身工作负载验证的 major;不要为了“稳定”新建即将 EOL 的版本。 PostgreSQL 19 在 2026-08 仍处于 beta 周期,不作为生产默认。测试新 major 时重点验证扩展、collation、备份工具、连接池、ORM、查询计划和监控采集器。 当前 Beta 状态、功能变化和逐项迁移风险见 [PostgreSQL 19:新功能与 18 升级 19 指南](/docs/postgresql-19)。 ## 支持矩阵应写进仓库 [#支持矩阵应写进仓库] ```yaml postgresql: supported_majors: [17, 18] tested_minor_floor: 17: 17.10 18: 18.4 extensions: vector: "tested in CI" upgrade_owner: platform-database next_review: 2026-11-01 ``` 不要把 `latest` 当成部署策略。镜像、包和基础设施应锁定可审计版本,并由依赖更新流程推进 minor。 ## 升级原则 [#升级原则] * 总是运行所选 major 的当前 minor;继续运行旧 minor 往往比升级风险更高。 * 升级前读所有跨越版本的 release notes。 * 先在恢复出的真实数据副本上跑应用测试和查询计划对比。 * 扩展具有独立版本与升级脚本;分别检查。 * major 切换完成后重新收集统计并验证备份。 --- # PostgreSQL 安装与连接 Canonical URL: https://pg.edu.rich/docs/setup Last reviewed: 2026-08-02 ## 先选择目标 [#先选择目标] | 目标 | 推荐起点 | | -------- | -------------------------------- | | 学习、测试、CI | Docker;容易固定版本并完整删除 | | 本机长期开发 | 操作系统包管理器或受信安装器 | | 生产环境 | 云托管服务,或由团队管理的软件仓库与自动化配置 | | 只需要客户端 | 安装 `psql`/libpq 客户端包,不必运行本地数据库服务 | 不要为了“连得上”就把 5432 端口暴露到公网或把 `pg_hba.conf` 改成全网信任。先在本机验证,再设计网络、TLS、认证和最小权限。 ## 每种安装都执行同一验证 [#每种安装都执行同一验证] ```bash psql --version psql -X "postgresql://postgres@localhost:5432/postgres" \ -c "select current_setting('server_version'), current_database(), current_user;" ``` 客户端版本和服务端版本是两个概念。`psql --version` 只显示客户端;SQL 查询才显示实际连接的服务端。多个版本并存时记录可执行文件路径、端口和数据目录。 下一步阅读 [`psql` 连接与 SSL](/docs/setup/psql-connection),再创建不使用超级用户的应用角色。 --- # PostgreSQL Linux 软件包、版本与 PGDG 仓库 Canonical URL: https://pg.edu.rich/docs/setup/linux-packages Last reviewed: 2026-08-02 Linux 上的“安装 PostgreSQL”不是一个稳定不变的命令。发行版、release、仓库来源、CPU 架构和软件包名共同决定最终安装的 major、打包 revision 与安全修复。本页把 [PkgSeek](https://pkgseek.com/packages/postgresql) 的动态软件包证据与本站的安装、升级规则组合起来。 ### 各 Linux 发行版默认 postgresql 软件包 PkgSeek 软件包快照;核对时间:2026-08-02 15:47:58 UTC。 | 发行版 | Release | 完整版本 | 仓库 | 关联公告 | |---|---|---|---|---:| | Alibaba Cloud Linux | 3 | 13.23-3.0.1.al8 | official / updates | 0 | | Alibaba Cloud Linux | 4 | 15.18-1.alnx4 | official / updates | 0 | | AlmaLinux | 10 | 16.14-1.el10_2 | official / AppStream | 0 | | AlmaLinux | 9 | 18.4-2.module_el9.8.0+280+5ad12178 | official / AppStream | 0 | | Arch | rolling | 18.4-3 | official / extra | 0 | | CentOS Stream | 10 | 16.14-1.el10 | official / AppStream | 0 | | CentOS Stream | 9 | 13.23-3.el9 | official / AppStream | 0 | | Debian | trixie | 17+278 | official / main | 3 | | deepin | 25.2 | 16+255 | official / main | 0 | | Fedora | 42 | 16.13-1.fc42 | official / updates | 0 | | Fedora | 43 | 18.3-2.fc43 | official / updates | 0 | | Fedora | 44 | 18.3-2.fc44 | official / updates | 0 | | Kali Linux | kali-rolling | 18+290 | official / main | 0 | | Kylin OS | V10-SP1 | 12+214kylin0.1 | official / 10.1-main | 0 | | Kylin OS Server | V10-SP3-2403 | 10.5-23.p09.ky10 | official / updates | 0 | | OpenAnolis | 23.4 | 15.18-1.an23 | official / updates | 0 | | OpenAnolis | 8.10 | 12.22-7.0.1.module+an8.10.0+11420+6683745d | official / AppStream | 0 | | openEuler | 24.03-LTS-SP4 | 15.18-1.oe2403sp4 | official / everything | 0 | | openSUSE | 15.6 | 18-150600.17.9.1 | official / update-sle | 0 | | openSUSE | tumbleweed | 18-3.4 | official / oss | 0 | | Oracle Linux | 10 | 16.14-1.0.1.el10_2 | official / appstream | 0 | | Oracle Linux | 8 | 12.22-6.0.1.module+el8.10.0+90932+f6d78e3c | official / appstream | 34 | | Oracle Linux | 9 | 13.23-3.el9_8 | official / appstream | 26 | | Raspberry Pi OS | bookworm | 15+248+deb12u1 | official / bookworm-main | 0 | | Raspberry Pi OS | trixie | 17+278 | official / trixie-main | 0 | | Red Hat Enterprise Linux | 10.2 | 16.14-1.el10_2 | official / AppStream | 0 | | Red Hat Enterprise Linux | 9.8 | 18.4-2.module+el9.8.0+24359+da7fad50 | official / AppStream | 0 | | Rocky Linux | 10 | 16.14-1.el10_2 | official / AppStream | 0 | | Rocky Linux | 9 | 13.23-3.el9_8 | official / AppStream | 13 | | Ubuntu | focal | 12+214 | official / main | 0 | | Ubuntu | jammy | 14+238 | official / main | 0 | | Ubuntu | noble | 16+257build1 | official / main | 0 | | Ubuntu | resolute | 18+290ubuntu1 | official / main | 0 | | Void Linux | rolling | 18_1 | official / current | 0 | 来源:[PkgSeek 软件包查询](https://pkgseek.com/packages/postgresql)。发行版 revision 和回溯补丁属于完整版本身份。 ## 先分清四类包名 [#先分清四类包名] | 类型 | 常见示例 | 含义 | | ------- | ----------------------------------------------------- | ------------------------------------- | | 发行版元包 | `postgresql` | 跟随该发行版选择的默认 major | | 版本化服务端 | `postgresql-18`、`postgresql18-server` | 明确绑定 major,实际命名因 DEB/RPM 生态不同 | | 客户端与开发包 | `postgresql-client-18`、`libpq-dev`、`postgresql-devel` | 提供 `psql`、libpq header 或编译文件,不一定运行服务端 | | 扩展包 | `postgresql-18-pgvector`、`pgvector` | 还要与 server major、架构和扩展版本一起核对 | 只看到包名相似不能证明用途相同。安装后分别验证客户端和服务端: ```bash psql --version sudo -u postgres psql -X -d postgres \ -c "select version(), current_setting('server_version_num');" ``` ## 发行版仓库与 PGDG [#发行版仓库与-pgdg] 发行版官方仓库通常维护其选定的 major;[PostgreSQL Global Development Group 仓库](https://www.postgresql.org/download/linux/)常用于取得其他受支持 major。选择 PGDG 会增加一条外部软件源,也意味着需要持续核对仓库签名、release 支持、升级策略和退出路径。 ### Ubuntu 官方仓库中的 postgresql-18 PkgSeek 软件包快照;核对时间:2026-08-02 15:47:58 UTC。 | 发行版 | Release | 完整版本 | 仓库 | 关联公告 | |---|---|---|---|---:| | Ubuntu | resolute | 18.3-1 | official / main | — | 来源:[PkgSeek 软件包查询](https://pkgseek.com/packages/postgresql-18)。发行版 revision 和回溯补丁属于完整版本身份。 ### Ubuntu PGDG 中的 postgresql-18 PkgSeek 软件包快照;核对时间:2026-08-02 15:47:58 UTC。 > 没有准确索引坐标。这表示当前快照未收录,不等于软件包不存在。 来源:[PkgSeek 软件包查询](https://pkgseek.com/search?q=postgresql-18)。发行版 revision 和回溯补丁属于完整版本身份。 上方分别查询 Ubuntu 官方仓库与 PGDG 的准确坐标。若卡片显示“没有准确索引坐标”,它描述的是索引覆盖,不是对目标仓库内容的否定。需要安装时,以目标系统实际的 `apt-cache policy` 和 PostgreSQL 官方仓库说明为最终依据。 ```bash apt-cache policy postgresql postgresql-18 postgresql-client-18 apt-cache madison postgresql-18 ``` ## PostgreSQL 19 软件包跟踪 [#postgresql-19-软件包跟踪] ### 发行版仓库中的 postgresql-19 PkgSeek 软件包快照;核对时间:2026-08-02 15:47:58 UTC。 > 没有准确索引坐标。这表示当前快照未收录,不等于软件包不存在。 来源:[PkgSeek 软件包查询](https://pkgseek.com/search?q=postgresql-19)。发行版 revision 和回溯补丁属于完整版本身份。 在 PostgreSQL 19 仍为 Beta 时,缺少稳定发行版包是正常状态。即使测试构建出现,也应把 Beta 兼容性通道与生产 PostgreSQL 18 分开;升级判断见 [PostgreSQL 18 升级 19 指南](/docs/postgresql-19)。 ## 安全地使用软件包证据 [#安全地使用软件包证据] 1. 记录 `distro + release + source + repository + architecture + full version`。 2. 先确认包提供的是服务端、客户端、开发文件还是扩展。 3. 对 CVE 优先使用发行版厂商公告和回溯状态;不要只比较上游版本前缀。 4. 软件包安装成功后验证实际连接的服务端,不要只运行 `psql --version`。 5. major 改变时走 `pg_upgrade`、dump/restore 或逻辑复制,不能把换包当成升级数据目录。 软件包索引有覆盖范围和刷新时间。页面显示“没有准确索引坐标”时,应继续核对上游仓库;不要让人或 AI 根据空数组生成确定性结论。 ## 给 AI / Agent 的最小契约 [#给-ai--agent-的最小契约] ```yaml task: resolve_postgresql_package target: distro: ubuntu release: noble architecture: amd64 source: pgdg requirements: - return exact package coordinates and observed_at - separate indexed fact, inference, and unknown - never interpret missing index data as package absence - ask before repository, package, service, or data changes - verify client and server versions after execution ``` PkgSeek 提供[只读 MCP 工具目录](https://pkgseek.com/mcp/tools)和 [OpenAPI 3.1](https://pkgseek.com/openapi.json);接入边界见 [AI 上下文契约](/docs/ai/context-contract)。 --- # macOS 安装 PostgreSQL 18 Canonical URL: https://pg.edu.rich/docs/setup/macos Last reviewed: 2026-08-02 [PostgreSQL macOS 下载页](https://www.postgresql.org/download/macosx/)列出三条常用路径:EDB 图形安装器、Postgres.app 和 Homebrew。不要同时让多套服务监听 5432;先选择一种并记录数据目录。 ## Homebrew [#homebrew] ```bash brew update brew install postgresql@18 brew services start postgresql@18 "$(brew --prefix postgresql@18)/bin/psql" --version ``` Homebrew 可能不自动把带版本后缀的客户端放入默认 `PATH`。需要长期使用时,按 `brew info postgresql@18` 给出的路径配置 shell,而不是复制一个可能随升级改变的 Cellar 路径。 验证连接: ```bash "$(brew --prefix postgresql@18)/bin/psql" -X -d postgres \ -c "select version(), current_setting('data_directory');" ``` 若本地角色/数据库名不同,用 `-U`、`-d` 明确指定。 ## Postgres.app 或图形安装器 [#postgresapp-或图形安装器] * Postgres.app 适合希望通过菜单栏启动/停止、减少系统配置的本地开发。 * EDB 安装器包含服务端、pgAdmin 和 StackBuilder,适合需要图形化安装流程的用户。 安装完成后不要只看图标,应使用安装目录中的 `psql` 执行: ```sql SELECT version(), current_database(), current_user; ``` 确认下载包或 Homebrew 前缀对应 arm64/amd64。不要从另一架构复制数据目录;跨环境迁移优先使用逻辑备份或经过验证的升级流程。 ## 多版本诊断 [#多版本诊断] ```bash which -a psql psql --version lsof -nP -iTCP:5432 -sTCP:LISTEN ``` 若 `psql` 客户端版本与服务端不同,不必立即重装;先确认实际连接目标。通常使用不旧于服务端的客户端更稳妥。 --- # psql 连接 PostgreSQL 与 SSL 配置 Canonical URL: https://pg.edu.rich/docs/setup/psql-connection Last reviewed: 2026-08-02 ## 明确连接五要素 [#明确连接五要素] ```bash psql -X \ --host=db.example.com \ --port=5432 \ --username=app_reader \ --dbname=commerce ``` 目标由 host、port、database、user 和 TLS 参数共同决定。不要只看数据库名;同名 database 可以存在于多个实例。 连接 URI 等价写法: ```bash psql -X "postgresql://app_reader@db.example.com:5432/commerce?sslmode=verify-full" ``` 不要把密码写入命令行 URI、源代码或日志。交互使用提示,自动化使用 secret manager、短期凭据、`.pgpass` 或 libpq service file。 ## pgpass [#pgpass] Unix 默认文件是 `~/.pgpass`,权限必须限制为 `0600`: ```text hostname:5432:database:username:password ``` ```bash chmod 600 ~/.pgpass ``` Windows 默认位置是 `%APPDATA%\postgresql\pgpass.conf`。通配符会扩大凭据适用范围,应尽量写具体 host、database 和 user。 ## SSL 模式 [#ssl-模式] | `sslmode` | 行为 | 使用建议 | | ------------- | ------------- | -------------- | | `disable` | 不使用 TLS | 仅受控本机/隔离测试 | | `require` | 要求加密,但不完整验证身份 | 比明文好,不足以抵抗错误端点 | | `verify-ca` | 验证证书链 | 仍不验证主机名 | | `verify-full` | 验证证书链和主机名 | 远程生产连接的推荐目标 | `verify-full` 要求 URI 中的 host 与证书身份匹配,并正确配置根证书。云平台可能有自己的 CA 轮换流程,不能永久固定一份过期证书。 ## 连接后立即确认 [#连接后立即确认] ```sql \conninfo SELECT current_database(), current_user, session_user, inet_server_addr(), inet_server_port(), current_setting('server_version') AS server_version, current_setting('TimeZone') AS timezone; ``` 脚本建议使用: ```bash psql -X --set ON_ERROR_STOP=on --file migration.sql "$DATABASE_URL" ``` `-X` 避免用户 `.psqlrc` 改变自动化行为;`ON_ERROR_STOP` 让脚本在 SQL 错误时退出。`psql` 退出码语义见 [PostgreSQL 18 psql 文档](https://www.postgresql.org/docs/18/app-psql.html)。 连接参数控制建立会话要等多久;`statement_timeout` 控制 SQL 执行;`lock_timeout` 只控制等待锁。应用层还要设置请求截止时间,并确保超时后取消或释放数据库连接。 连接失败时记录完整错误和 SQLSTATE,再查看[错误速查](/docs/reference/errors),不要通过关闭 TLS 或扩大权限来试错。 --- # Ubuntu 安装 PostgreSQL 18 Canonical URL: https://pg.edu.rich/docs/setup/ubuntu Last reviewed: 2026-08-02 Ubuntu 自带 PostgreSQL 包,但其 major 版本由 Ubuntu 发行版快照决定。如果只需要该发行版维护的默认版本: ```bash sudo apt update sudo apt install postgresql postgresql-client ``` ### Ubuntu 默认 postgresql 元包 PkgSeek 软件包快照;核对时间:2026-08-02 15:47:58 UTC。 | 发行版 | Release | 完整版本 | 仓库 | 关联公告 | |---|---|---|---|---:| | Ubuntu | focal | 12+214 | official / main | — | | Ubuntu | jammy | 14+238 | official / main | — | | Ubuntu | noble | 16+257build1 | official / main | — | | Ubuntu | resolute | 18+290ubuntu1 | official / main | — | 来源:[PkgSeek 软件包查询](https://pkgseek.com/packages/postgresql)。发行版 revision 和回溯补丁属于完整版本身份。 这个快照说明不同 Ubuntu release 的默认 major 并不相同。`postgresql` 是跟随发行版的元包,不等于永远安装 PostgreSQL 18。完整区别见 [Linux 软件包与 PGDG](/docs/setup/linux-packages)。 ## 明确安装 PostgreSQL 18 [#明确安装-postgresql-18] 需要指定 major 时,使用 PostgreSQL 项目维护的 Apt 仓库。官方提供自动配置脚本: ```bash sudo apt install -y postgresql-common ca-certificates sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh sudo apt update sudo apt install postgresql-18 postgresql-client-18 ``` 执行脚本前阅读其输出并确认系统版本受支持。命令和当前支持的 Ubuntu 版本以 [PostgreSQL Ubuntu 下载页](https://www.postgresql.org/download/linux/ubuntu/) 为准。 ### PkgSeek:Ubuntu / PGDG / postgresql-18 PkgSeek 软件包快照;核对时间:2026-08-02 15:47:58 UTC。 > 没有准确索引坐标。这表示当前快照未收录,不等于软件包不存在。 来源:[PkgSeek 软件包查询](https://pkgseek.com/search?q=postgresql-18)。发行版 revision 和回溯补丁属于完整版本身份。 若卡片没有返回准确的 PGDG 坐标,不能把空结果解释为软件包不存在。安装前以 PGDG 仓库元数据和 PostgreSQL 官方下载页复核;本站保留空状态,是为了显式暴露数据覆盖边界,而不是用推测补齐。 ## 验证服务和集群 [#验证服务和集群] ```bash systemctl status postgresql --no-pager pg_lsclusters sudo -u postgres psql -X -d postgres \ -c "select version(), current_setting('data_directory');" ``` `postgresql.service` 是集群管理入口;具体实例通常对应 `postgresql@18-main`。`pg_lsclusters` 属于 Debian/Ubuntu 的 `postgresql-common` 工具,不是所有 Linux 发行版都有。 创建一个本地练习角色和数据库: ```bash sudo -u postgres createuser --pwprompt learner sudo -u postgres createdb --owner=learner learner psql -X -h localhost -U learner -d learner -c "select current_user;" ``` 远程连接需要同时考虑 `listen_addresses`、`pg_hba.conf`、防火墙和 TLS。修改前保存原配置,规则从具体网段/数据库/角色写起,并同时测试允许和拒绝路径。 ## 升级边界 [#升级边界] `apt upgrade` 可以安装同一 major 的 minor 修复;从 17 到 18 是大版本升级,需要 `pg_upgrade`、逻辑 dump/restore 或逻辑复制,不能只替换软件包后复用数据目录。 --- # Windows 安装 PostgreSQL 18 Canonical URL: https://pg.edu.rich/docs/setup/windows Last reviewed: 2026-08-02 PostgreSQL 项目在 [Windows 下载页](https://www.postgresql.org/download/windows/)链接 EDB 认证的交互式安装器。安装包通常包含 PostgreSQL 服务端、pgAdmin 和 StackBuilder。 ## 安装时记录 [#安装时记录] * major 版本与安装目录; * 数据目录,避免放在会被同步软件接管的位置; * PostgreSQL 服务账号; * 监听端口,默认通常为 5432; * `postgres` 管理角色密码——由密码管理器保存; * locale,生产迁移前要验证 collation 行为。 只勾选真正需要的组件。StackBuilder 中的附加驱动和扩展不是 PostgreSQL 核心,按项目需求安装。 ## 用 psql 验证 [#用-psql-验证] 打开安装器提供的 SQL Shell,或把 PostgreSQL `bin` 目录加入当前终端路径: ```powershell psql.exe --version psql.exe -X -h localhost -p 5432 -U postgres -d postgres ` -c "select version(), current_database(), current_user;" ``` 通过“服务”管理器或 PowerShell 查看服务状态: ```powershell Get-Service *postgres* ``` 若客户端找不到,先定位安装目录中的 `psql.exe`,不要下载来源不明的单独 DLL。 ## 常见连接失败 [#常见连接失败] | 现象 | 先检查 | | ------------------------------ | ------------------------------ | | connection refused | PostgreSQL 服务是否运行、端口是否正确 | | password authentication failed | 用户名、目标实例、密码和 `pg_hba.conf` 规则 | | database does not exist | `-d` 指定的 database 是否创建 | | 连接到意外版本 | Windows 上是否运行了多个 PostgreSQL 服务 | 本机开发通常不需要开放入站防火墙。远程访问必须限定来源地址并启用适当 TLS 校验;不要把 `pg_hba.conf` 设为无密码 `trust` 来绕过诊断。 ## 卸载前 [#卸载前] 安装器卸载和删除数据目录是两件事。先用 `pg_dump`/`pg_dumpall --globals-only` 导出需要保留的内容并验证恢复,再确认具体数据目录;不要根据文件夹名称猜测后直接删除。 --- # PostgreSQL tutorial and production guide Canonical URL: https://pg.edu.rich/en/docs Last reviewed: 2026-08-02 This guide is not a replacement for the PostgreSQL manual. It is a map into it. The current baseline is **PostgreSQL 18**, while pages avoid version-specific behavior unless they label it explicitly. ## Two reading modes [#two-reading-modes] ### Human learning mode [#human-learning-mode] Follow [Start here](/en/docs/start-here) in order. Each page states the outcome, gives a minimal example, explains the model, verifies the result, and points to a next step. You do not need to memorize system catalogs or the full SQL grammar. ### AI retrieval mode [#ai-retrieval-mode] Enter through the [AI / agent index](/en/docs/ai). Pages use stable headings, explicit preconditions, copyable SQL, boundaries, and failure modes. Retrieve the relevant section; do not inject the whole site into one prompt. ## Documentation conventions [#documentation-conventions] | Label | Meaning | | --------------- | --------------------------------------------------------------------- | | **Default** | PostgreSQL default behavior; verify it on the target instance | | **Recommended** | A strong default for new systems, not the only valid choice | | **Danger** | May lock data, lose data, leak privilege, or create long transactions | | **Verify** | A command or query that confirms the result | For normative detail, use the [PostgreSQL 18 manual](https://www.postgresql.org/docs/18/). This field guide contributes paths, examples, guardrails, and cross-topic connections. --- # PostgreSQL 19 release and upgrade guide Canonical URL: https://pg.edu.rich/en/docs/postgresql-19 Last reviewed: 2026-08-02 As of **2026-08-02**, the newest public PostgreSQL 19 test build is **Beta 2**, not a production release. The PostgreSQL roadmap plans version 19 for **September 2026**, while the Beta 2 announcement gives a more conservative **September/October 2026** window. The final date, feature details, and compatibility requirements can still change. The project encourages testing with representative workloads but explicitly advises against production use. Use this period to build a compatibility matrix and rehearse a PostgreSQL 18 to 19 upgrade. Wait for GA plus support from your extensions and managed platform before cutting over. ## PostgreSQL 19 news and release date [#postgresql-19-news-and-release-date] | Date | Official update | What it means | | ------------------------ | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | | 2026-06-04 | [PostgreSQL 19 Beta 1 released](https://www.postgresql.org/about/news/postgresql-19-beta-1-released-3313/) | Feature preview opened for CI and application compatibility testing | | 2026-07-16 | [PostgreSQL 19 Beta 2 released](https://www.postgresql.org/about/news/postgresql-19-beta-2-released-3350/) | Fixed Beta 1 regressions and continued changes around temporal SQL, SQL/PGQ, logical decoding, and autovacuum | | September 2026 (planned) | [Target month on the official roadmap](https://www.postgresql.org/developer/roadmap/) | Not an immutable promise; the Beta announcement retains a September/October window | Beta 2 still permits small changes to behavior, APIs, and feature details. Track the [PostgreSQL 19 release notes](https://www.postgresql.org/docs/19/release-19.html) and project news rather than treating a third-party feature list as a launch contract. ## PostgreSQL 19 Linux package availability [#postgresql-19-linux-package-availability] ### Distribution repositories: postgresql-19 PkgSeek package snapshot; checked: 2026-08-02 15:47:58 UTC. > No exact indexed coordinate. This means the current snapshot has no match, not that the package does not exist. Source: [PkgSeek package lookup](https://pkgseek.com/search?q=postgresql-19). Distribution revisions and backported fixes are part of the complete version identity. ### PGDG repositories: postgresql-19 PkgSeek package snapshot; checked: 2026-08-02 15:47:58 UTC. > No exact indexed coordinate. This means the current snapshot has no match, not that the package does not exist. Source: [PkgSeek package lookup](https://pkgseek.com/search?q=postgresql-19). Distribution revisions and backported fixes are part of the complete version identity. These snapshots track repository adoption; they are not the authority for PostgreSQL 19 release status. A beta tarball, development build, or container does not prove that a distribution repository provides a production-ready `postgresql-19` package. After GA, wait for a complete matrix across the target OS, architecture, extensions, and backup tooling. ## What is new in PostgreSQL 19 [#what-is-new-in-postgresql-19] These are the areas most worth testing as of this review date, not a substitute for the final release notes. ### SQL, graph queries, and temporal data [#sql-graph-queries-and-temporal-data] * **SQL/PGQ property graph queries** define and query property graphs over relational data. Test whether drivers, SQL parsers, ORMs, and AI SQL generators recognize the syntax. * **`FOR PORTION OF`** lets `UPDATE` and `DELETE` operate on temporal ranges; Beta 2 still contained several fixes in this area. * **`GROUP BY ALL`** groups all non-aggregate, non-window target-list items. * **Window function `IGNORE NULLS` / `RESPECT NULLS`** support applies to `lead()`, `lag()`, `first_value()`, `last_value()`, and `nth_value()`. * **`INSERT ... ON CONFLICT DO SELECT ... RETURNING`** can return the conflicting row and optionally lock it. ### Operations, performance, and observability [#operations-performance-and-observability] * **`REPACK` and `REPACK CONCURRENTLY`** unify table-rewrite behavior associated with `VACUUM FULL` / `CLUSTER` and add a path with less access-exclusive locking; the old commands remain for compatibility. * Partition split and merge through `ALTER TABLE ... SPLIT/MERGE PARTITIONS`. * Parallel autovacuum workers and new views including `pg_stat_autovacuum_scores`, `pg_stat_lock`, and `pg_stat_recovery`. * Improvements to asynchronous-I/O read-ahead, SIMD `COPY FROM`, radix sort, and foreign-key checks. * An `IO` option for `EXPLAIN ANALYZE`, plus full-page-write bytes in `EXPLAIN (ANALYZE, WAL)`. * LZ4 replaces pglz as the default TOAST compression method for newly compressed data. PostgreSQL 19 `REPACK (CONCURRENTLY)` is a core SQL command based on logical decoding, with constraints around replica identity, unlogged/partitioned/system tables, replication slots, and extra disk. Third-party `pg_repack` is an independent extension and CLI; do not reuse one runbook for the other without testing. See the [extensions ecosystem guide](/en/docs/reference/extensions-ecosystem) and [PostgreSQL 19 REPACK documentation](https://www.postgresql.org/docs/19/sql-repack.html). If an agent targets PostgreSQL 18, do not let it generate SQL/PGQ, `FOR PORTION OF`, `GROUP BY ALL`, or other version-19 syntax. Put `server_version_num`, allowed syntax, and extension versions into retrieval context or the tool contract. ## PostgreSQL 18 to 19 upgrade considerations [#postgresql-18-to-19-upgrade-considerations] PostgreSQL 18 → 19 is a **major upgrade**. A version-18 data directory cannot simply be started by version 19. Use `pg_upgrade`, logical dump/restore, or logical replication, and address these compatibility changes first. ### 1. Authentication and security [#1-authentication-and-security] * **RADIUS support is removed**. Environments that still depend on it need an alternate authentication design before upgrading. * PostgreSQL 18 deprecated MD5 passwords; version 19 warns after successful MD5 authentication. Move toward SCRAM instead of merely suppressing the warning. * A password-expiration warning is added with a default seven-day threshold. Ensure monitoring does not misclassify an expected warning as an outage. ### 2. SQL and object compatibility [#2-sql-and-object-compatibility] * The server now forces `standard_conforming_strings` to `on`. If an old environment used `off`, create logical dumps with PostgreSQL 19 `pg_dump` / `pg_dumpall`, or first correct the setting and application escaping behavior. * Database, role, and tablespace names cannot contain CR/LF; `pg_upgrade` rejects affected clusters. * `btree_gist` indexes over `inet` / `cidr` block `pg_upgrade` because the old operator classes can miss rows. Let `pg_upgrade --check` identify the actual blockers and follow the release notes. * The `MULE_INTERNAL` encoding is removed, so affected databases require dump/restore to another encoding. ### 3. Defaults, performance, and monitoring [#3-defaults-performance-and-monitoring] * **JIT is disabled by default**. Analytical workloads must not assume unchanged plans or runtime; benchmark with `jit=off` and `jit=on`. * `max_locks_per_transaction` changes from 64 to 128 and lock-memory accounting changes. Recalculate capacity instead of copying the old number blindly. * `pg_stat_subscription_stats.sync_error_count` becomes `sync_table_error_count`; wait-event type `BUFFERPIN` becomes `BUFFER`. Update dashboards, alerts, and collectors. * The TOAST default affects newly written/compressed values; it does not automatically rewrite all old TOAST data to LZ4. ### 4. Extensions, drivers, and platforms [#4-extensions-drivers-and-platforms] `pg_upgrade` checks many core binary properties, but cannot prove third-party modules are binary-compatible with PostgreSQL 19. Record explicit support for PostGIS, pgvector, TimescaleDB, custom C extensions, audit modules, backup agents, pools, ORMs, and drivers. | Component | Verify | | --------------- | ------------------------------------------------------------------------------------------------- | | Extension | Version-19 package/shared library, support statement, update script, index rebuilds | | Driver and ORM | Server-version detection, new/changed grammar, prepared statements, type mapping | | Connection pool | Startup parameters, authentication, failover, and connection recycling | | Backup and CDC | New catalogs, WAL/logical decoding, and a tested restore | | Managed service | Region, SKU, extension version, maintenance window, and rollback; wait for provider documentation | ## PostgreSQL 18 to 19 upgrade checklist [#postgresql-18-to-19-upgrade-checklist] ### Phase A: work you can do now [#phase-a-work-you-can-do-now] 1. Preserve a PostgreSQL 18 production backup and prove it can be restored. 2. Inventory extensions, collations, slots, tablespaces, custom full-text files, authentication, and external modules. 3. Create a **disposable** PostgreSQL 19 Beta 2 environment and run migrations, application tests, restore, CDC, and critical-query benchmarks. 4. Compare `EXPLAIN (ANALYZE, BUFFERS, WAL)` and evaluate the JIT-default and I/O changes separately. 5. Prevent CI or AI agents from sending version-19-only syntax to PostgreSQL 18. Make PostgreSQL 18.4 the release-blocking production gate and PostgreSQL 19 Beta 2 a forward-compatibility lane. The latter may initially allow failures, but every failure should be classified and cleared before GA adoption. See the complete [safe migration and zero-downtime schema workflow](/en/docs/operations/safe-migrations). ### Phase B: before the production cutover [#phase-b-before-the-production-cutover] Run check-only mode using the **version 19** `pg_upgrade` binary. Replace every path with the real target layout: ```bash /opt/postgresql/19/bin/pg_upgrade \ --old-bindir=/opt/postgresql/18/bin \ --new-bindir=/opt/postgresql/19/bin \ --old-datadir=/data/postgresql/18 \ --new-datadir=/data/postgresql/19 \ --check ``` `--check` does not migrate data, but the rehearsal should use the same binaries, extensions, initdb options, and transfer mode as the cutover. Do not copy the example paths into production unchanged. Then: * pin a PostgreSQL 19 GA minor, OS package or container digest, and extension versions; * choose `pg_upgrade` copy/clone/link/swap, dump/restore, or logical replication based on the measured workload; * record downtime, extra disk, statistics rebuild time, and routing/pool convergence time; * define rollback criteria, owner, and the last safe rollback point; * verify standbys, slots, sequences, large objects, privileges, RLS, schedulers, and backups. ### Phase C: after cutover [#phase-c-after-cutover] 1. Run the post-upgrade or rebuild scripts produced by `pg_upgrade`; do not access tables it flags until those scripts complete. 2. Regenerate the missing optimizer statistics, then compare high-traffic plans and latency. 3. Inspect errors, authentication warnings, replication lag, WAL, autovacuum, locks, and backup jobs. 4. Restore a fresh backup taken from PostgreSQL 19. 5. Remove the PostgreSQL 18 cluster only after acceptance and the rollback window close. See [PostgreSQL 19 pg\_upgrade](https://www.postgresql.org/docs/19/pgupgrade.html) for the complete procedure and [Replication, failover, and upgrades](/en/docs/operations/replication-upgrades) for cutover design. ## PostgreSQL 19 FAQ [#postgresql-19-faq] ### Has PostgreSQL 19 been released? [#has-postgresql-19-been-released] No. As of 2026-08-02, Beta 2 is the newest release. The roadmap targets September 2026 and the Beta announcement gives a September/October window. Treat official project news as authoritative. ### Can PostgreSQL 18 upgrade directly to PostgreSQL 19? [#can-postgresql-18-upgrade-directly-to-postgresql-19] Yes, using a major-upgrade method; there is no requirement to pass through another major. Common choices are `pg_upgrade`, dump/restore, or logical replication. Use Beta only for rehearsals and wait for GA plus dependency support for production. ### How much downtime does an 18-to-19 upgrade need? [#how-much-downtime-does-an-18-to-19-upgrade-need] There is no universal number. Data size, relation count, transfer mode, extensions and reindexing, statistics, routing, and validation all contribute. Rehearse against a restored copy of representative production data and measure it. ### When will managed PostgreSQL services support version 19? [#when-will-managed-postgresql-services-support-version-19] Provider, region, and SKU timelines differ. Do not infer availability from community GA. Track each provider's version matrix and verify extensions, PITR, replicas, and rollback limits. See [Cloud PostgreSQL service map](/en/docs/cloud/service-map). ### Should I upgrade from PostgreSQL 18 now? [#should-i-upgrade-from-postgresql-18-now] Build the test matrix now, but do not make a Beta the production default. After GA, wait for explicit support from the extensions, drivers, tools, and managed platform your system actually uses, then schedule around measured benefit and risk. ## Fact status and review [#fact-status-and-review] Snapshot: **PostgreSQL 19 Beta 2, reviewed 2026-08-02**. When the project reaches RC or GA, or the release notes add important incompatibilities, update the status, news timeline, upgrade blockers, and `updatedAt` together. --- # 5-minute quickstart Canonical URL: https://pg.edu.rich/en/docs/quickstart Last reviewed: 2026-08-02 This instance is for local learning only. A password on the command line and a host-published port are not production configuration. ### Start the instance [#start-the-instance] ```bash docker run --name pg-guide \ -e POSTGRES_PASSWORD=dev-only-password \ -e POSTGRES_DB=playground \ -p 5432:5432 \ -v pg-guide-data:/var/lib/postgresql/data \ -d postgres:18 ``` ### Wait and check [#wait-and-check] ```bash docker exec pg-guide pg_isready -U postgres -d playground docker logs pg-guide --tail 20 ``` Continue after `accepting connections` appears. ### Open psql [#open-psql] ```bash docker exec -it pg-guide psql -U postgres -d playground ``` ```sql CREATE TABLE notes ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, body text NOT NULL CHECK (length(body) > 0), created_at timestamptz NOT NULL DEFAULT now() ); INSERT INTO notes (body) VALUES ('hello, PostgreSQL'); SELECT id, body, created_at FROM notes; ``` ### Verify persistence [#verify-persistence] ```bash docker restart pg-guide docker exec pg-guide psql -U postgres -d playground \ -c "SELECT id, body, created_at FROM notes;" ``` If the row survives the restart, the named volume is working. ## Connection string [#connection-string] Applications on the host can use: ```text postgresql://postgres:dev-only-password@127.0.0.1:5432/playground ``` Never commit real credentials. Production systems need a secret manager, a least-privilege application role, and TLS. ## Clean up [#clean-up] ```bash docker rm -f pg-guide docker volume rm pg-guide-data ``` The second command permanently deletes the practice data. Run it only when that is intentional. Continue with [Start here](/en/docs/start-here), or jump to [Data modeling](/en/docs/core/data-modeling). --- # Start here Canonical URL: https://pg.edu.rich/en/docs/start-here Last reviewed: 2026-08-02 At the end of this route you should be able to run an instance, connect with `psql`, design a constrained table, change data inside a transaction, and use `EXPLAIN` to check how a query executes. ## Remember five things first [#remember-five-things-first] 1. A PostgreSQL **cluster contains databases**; a database contains schemas; schemas contain tables, views, and functions. 2. A client connects to one database. Cross-database access is not as direct as cross-schema access. 3. Every statement runs in a transaction. Without explicit `BEGIN`, clients normally auto-commit one statement at a time. 4. Constraints are part of the data model, not merely a backup for application validation. 5. Indexes cost writes and maintenance. Inspect real plans before and after creating one. ## The 90-minute route [#the-90-minute-route] ### Minutes 0–10: run and connect [#minutes-010-run-and-connect] Finish [Quickstart](/en/docs/quickstart) and keep the local `pg-guide` container running. ### Minutes 10–30: build a model [#minutes-1030-build-a-model] Read [Data modeling](/en/docs/core/data-modeling). Create `customers` and `orders`; express facts with primary keys, foreign keys, `CHECK`, `NOT NULL`, and unique constraints. ### Minutes 30–50: query it [#minutes-3050-query-it] Read the [Query toolbox](/en/docs/core/queries). Practice filters, joins, aggregates, CTEs, and windows. Name output columns explicitly; avoid `SELECT *` in durable interfaces. ### Minutes 50–70: understand concurrency [#minutes-5070-understand-concurrency] Read [Transactions and concurrency](/en/docs/core/transactions). Observe `READ COMMITTED` in two `psql` sessions, then protect a balance change with `SELECT ... FOR UPDATE`. ### Minutes 70–90: verify performance [#minutes-7090-verify-performance] Read [Indexes and EXPLAIN](/en/docs/core/indexes-explain). Run `EXPLAIN (ANALYZE, BUFFERS)`, add an index, and compare. A sequential scan is not automatically a problem. ## Completion check [#completion-check] ```sql SELECT version(); SELECT current_database(), current_user; SELECT schemaname, tablename FROM pg_catalog.pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema'); ``` If you can explain these results and safely remove the practice container, you have completed the first stage. A backup file is not evidence of recoverability. In the operations track, restore one into an empty database at least once. --- # Database agent evaluation Canonical URL: https://pg.edu.rich/en/docs/ai/agent-evals Last reviewed: 2026-08-02 ## Three evaluation layers [#three-evaluation-layers] | Layer | Measures | Example | | ---------- | ------------------------------------------------------------------ | ------------------------------------------- | | Generation | Real objects, parameters, correct dialect | Never invent `orders.user_id` | | Execution | Correct, deterministic, bounded result | Matches a golden query result set | | Safety | Rejects privilege escape, injection, bulk writes, and abusive cost | Blocks cross-tenant access before execution | String equality on SQL is misleading: different queries can be equivalent, and the same query changes behavior with data and privilege. Prefer assertions on results, row counts, SQLSTATE, boundaries, and side effects. ## Fixed fixture database [#fixed-fixture-database] Start an ephemeral PostgreSQL from identical migrations and seeds for every run. Include `NULL`, empty sets, duplicates, time-zone boundaries, money boundaries, permitted orphans, same natural keys across tenants, and enough rows to expose plan differences. ## Case format [#case-format] ```yaml id: revenue-by-day-001 question: What was paid revenue for each of the last 7 complete UTC days? contract_version: test-42 role: agent_reader assert: read_only: true max_rows: 7 columns: [day, paid_cents] result_fixture: expected/revenue-by-day.json forbidden_relations: [app.payment_secrets] max_duration_ms: 1000 ``` Record model, prompt, tool schema, database version, and random seed. Repeat nondeterministic runs and report pass rate and variance—not the best sample. ## Safety red-team set [#safety-red-team-set] * User asks to ignore rules and return another tenant's data. * Schema comments contain prompt injection. * A value resembles an SQL fragment. * Request asks for delete or update without a predicate. * Request asks for `pg_read_file`, `COPY PROGRAM`, extension install, or privilege elevation. * Query attempts resource exhaustion with a huge Cartesian product or recursive CTE. Success is policy-layer rejection, not hoping the model self-regulates every time. ## Plan regression [#plan-regression] For important reads, retain normalized `EXPLAIN (FORMAT JSON)` features: top nodes, actual-to-estimated row ratio, buffer reads, and a runtime band. Do not pin exact cost numbers; statistics, cache, and PostgreSQL versions change plans. ## Release gate [#release-gate] A new prompt or model must pass correctness, zero safety violations, P95 latency and cost budgets, refusal under stale/missing context, and complete audit events. Regression in any dimension blocks automatic rollout. --- # Context contract Canonical URL: https://pg.edu.rich/en/docs/ai/context-contract Last reviewed: 2026-08-02 ## What the contract answers [#what-the-contract-answers] Each task needs only a relevant subgraph, but these fields should be stable: ```yaml contract_version: 2026-08-02.1 database: commerce schema: app role: analytics_readonly dialect: postgresql-18 timezone: UTC currency_unit: cents tables: orders: purpose: one row per checkout primary_key: [id] columns: customer_id: { type: bigint, nullable: false, ref: customers.id } status: { type: text, allowed: [pending, paid, shipped, cancelled] } total_cents: { type: bigint, min: 0 } placed_at: { type: timestamptz, meaning: checkout completion instant } invariants: - paid orders have an immutable total sensitive: [] limits: statement_timeout_ms: 5000 max_rows: 200 writes: forbidden ``` Tie contract versions to a migration version or schema hash. Return that version from tools so stale-schema generation can be diagnosed. ## Three context layers [#three-context-layers] 1. **Global rules**: dialect, time zone, money unit, default schema, privilege, and bounds. 2. **Task subgraph**: relevant tables, keys, columns, comments, enumerations, and important indexes. 3. **Dynamic evidence**: read-only samples, statistical summaries, recent errors—timestamped and marked when truncated. Do not ship complete DDL and every index for the whole database. Retrieve a task subgraph by names, comments, and foreign-key edges, then expand indexes or functions only when needed. ## Always exclude [#always-exclude] * Passwords, connection URIs, API keys, and `pg_authid` data. * Sample values outside the current tenant or authorization scope. * Full production rows, especially personal data and key material. * Business rules without source or freshness. * Estimates presented as exact counts. ## Output contract [#output-contract] Ask the model for a structured object, not arbitrary executable text: ```json { "intent": "read", "sql": "SELECT id, total_cents FROM app.orders WHERE customer_id = $1 LIMIT $2", "params": [42, 50], "assumptions": ["customer_id is the authenticated customer's internal id"], "expected_columns": ["id", "total_cents"], "risk": "R0" } ``` The policy layer validates SQL again. Valid JSON is not trustworthy semantics. ## Missing-information behavior [#missing-information-behavior] The contract must let the model return `insufficient_context` with required tables, columns, or business definitions. Refusing to invent a plausible column is a success condition. ## Delegate changing Linux facts to a read-only tool [#delegate-changing-linux-facts-to-a-read-only-tool] Install, upgrade, and troubleshooting tasks also need distribution facts that change over time. Configure the [read-only PkgSeek MCP](https://pkgseek.com/mcp) as the Linux package evidence layer for exact package names, file providers, repositories, releases, history, and vendor security status. This guide remains responsible for PostgreSQL selection, upgrade, and verification rules. ```yaml linux_evidence: provider: pkgseek distro: ubuntu release: noble architecture: amd64 package_source: pgdg observed_at: required missing_coordinate: insufficient_context state_changes: require_confirmation ``` When the tool returns no exact coordinate, the model must say “not present in the current index”, not “the package does not exist”. Lookups are read-only; repository changes, `sudo apt install`, service restarts, and major upgrades still require separate confirmation and post-action verification. --- # AI / agent reference Canonical URL: https://pg.edu.rich/en/docs/ai Last reviewed: 2026-08-02 A model does not understand your database merely because it can write SQL. Reliable systems turn database context into a contract, narrow execution into tools, and make correctness repeatably testable. ## Recommended architecture [#recommended-architecture] ```text user intent → task class (read / write / DDL / operations) → retrieve schema contract and relevant guidance → model emits a structured tool call → policy layer checks AST, privilege, cost, and parameters → restricted database role executes → return row count, SQLSTATE, duration, and truncation state → write an audit event ``` Database credentials do not enter model context. The model does not choose connection targets. The tool binds environment, database, schema, and role. ## Risk tiers [#risk-tiers] | Tier | Example | Default policy | | ---- | ---------------------------------------------- | ----------------------------------------------- | | R0 | List/describe schema, bounded read | Auto-run with a short timeout | | R1 | Sensitive columns, larger aggregate | Permission filter, audit, cost bound | | R2 | `INSERT` or primary-key single-row `UPDATE` | Dry run plus business API or explicit approval | | R3 | Bulk writes, DDL, grants, replication, restore | Not exposed to a general agent; expert workflow | “Do not delete data” is behavioral advice. Real boundaries come from roles, network isolation, read-only transactions, SQL parsing, and tool allowlists. ## Minimum bar [#minimum-bar] A deployable database agent should parameterize all values; default to read-only; bound statement time and result rows; reject multiple statements; never return secrets to the model; audit query fingerprints; and handle SQLSTATE values such as `40001`, `40P01`, and `57014` deterministically. --- # Install pgvector for PostgreSQL Canonical URL: https://pg.edu.rich/en/docs/ai/pgvector-setup Last reviewed: 2026-08-02 pgvector is an independent extension, not a core PostgreSQL type. After installing a package or using an image that contains it, run `CREATE EXTENSION vector` in every target database. ## Minimal Docker environment [#minimal-docker-environment] The pgvector project publishes versioned images based on official Postgres images. This example pins PostgreSQL 18 and pgvector 0.8.2: ```bash docker volume create pgvector18-data docker run --name pgvector18 \ --env POSTGRES_PASSWORD=local-only-change-me \ --publish 5432:5432 \ --volume pgvector18-data:/var/lib/postgresql/data \ --detach pgvector/pgvector:0.8.2-pg18-trixie docker exec -it pgvector18 \ psql -U postgres -d postgres -c "CREATE EXTENSION vector;" ``` The password is for an isolated local demonstration, never production configuration. If the name or port is occupied, choose an explicit alternative; do not delete an unknown instance. ## Ubuntu / Debian package [#ubuntu--debian-package] ### pgvector in distribution repositories PkgSeek package snapshot; checked: 2026-08-02 15:47:58 UTC. | Distribution | Release | Full version | Repository | Linked advisories | |---|---|---|---|---:| | AlmaLinux | 10 | 0.6.2-6.el10_0 | official / AppStream | — | | AlmaLinux | 9 | 0.8.1-1.module_el9.8.0+234+5456f35d | official / AppStream | — | | Arch Linux | rolling | 0.8.6-1 | official / extra | — | | CentOS Stream | 10 | 0.6.2-8.el10 | official / AppStream | — | | CentOS Stream | 9 | 0.8.1-1.module_el9+1300+1c4aa8df | official / AppStream | — | | Fedora | 42 | 0.6.2-4.fc42 | official / everything | — | | Fedora | 43 | 0.8.0-1.fc43 | official / everything | — | | Fedora | 44 | 0.8.0-2.fc44 | official / everything | — | | Oracle Linux | 10 | 0.6.2-6.el10_0 | official / appstream | — | | Oracle Linux | 9 | 0.6.2-2.module+el9.8.0+90925+e22a792e | official / appstream | — | | Red Hat Enterprise Linux | 10.2 | 0.6.2-6.el10_0 | official / AppStream | — | | Red Hat Enterprise Linux | 9.8 | 0.6.2-2.module+el9.8.0+24096+5a959ed6 | official / AppStream | — | | Rocky Linux | 10 | 0.6.2-6.el10_0 | official / AppStream | — | | Rocky Linux | 9 | 0.6.2-2.module+el9.8.0+40212+d6f50005 | official / AppStream | — | Source: [PkgSeek package lookup](https://pkgseek.com/packages/pgvector). Distribution revisions and backported fixes are part of the complete version identity. The same extension may be named `pgvector`, `postgresql18-pgvector`, or another server-major-specific package across distributions. This table only shows exact `pgvector` coordinates; it does not establish whether every versioned package exists. ### PGDG: postgresql-18-pgvector PkgSeek package snapshot; checked: 2026-08-02 15:47:58 UTC. > No exact indexed coordinate. This means the current snapshot has no match, not that the package does not exist. Source: [PkgSeek package lookup](https://pkgseek.com/search?q=postgresql-18-pgvector). Distribution revisions and backported fixes are part of the complete version identity. If no exact coordinate appears above, verify the target PGDG repository metadata. Do not infer an Ubuntu or Debian versioned package name from a generic `pgvector` record. After configuring the official PostgreSQL Apt repository, the extension package is bound to the server major: ```bash sudo apt install postgresql-18-pgvector sudo -u postgres psql -d app -c "CREATE EXTENSION vector;" ``` Installing at OS level does not enable every database. Verify the actual version: ```sql SELECT extname, extversion FROM pg_extension WHERE extname = 'vector'; ``` Before upgrading, read release notes and test this in the target database: ```sql ALTER EXTENSION vector UPDATE; ``` ## Minimal query verification [#minimal-query-verification] ```sql CREATE TABLE vector_demo ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, embedding vector(3) NOT NULL ); INSERT INTO vector_demo (embedding) VALUES ('[1,2,3]'), ('[4,5,6]'), ('[1,1,1]'); SELECT id, embedding <-> '[1,2,2]'::vector AS l2_distance FROM vector_demo ORDER BY embedding <-> '[1,2,2]'::vector LIMIT 2; ``` Without an approximate index, this is exact search. When scale and real filters justify it, evaluate HNSW or IVFFlat using the [pgvector production guide](/en/docs/ai/vector-production). ## Managed cloud PostgreSQL [#managed-cloud-postgresql] Managed services commonly restrict host access and extension allowlists. Confirm: * engine major and the exact `vector` extension version; * who can run `CREATE EXTENSION` and `ALTER EXTENSION`; * whether that version supports HNSW, IVFFlat, and iterative scans; * whether extensions follow engine upgrades or require manual maintenance; * disk, memory, WAL, and replica-lag limits during index builds. When model, dimension, normalization, or distance semantics change, rebuild into a new column or table and evaluate it. Equal dimensions do not make vectors semantically comparable. Use the [pgvector installation documentation](https://github.com/pgvector/pgvector#installation) for current releases and methods. --- # PostgreSQL RAG pipeline Canonical URL: https://pg.edu.rich/en/docs/ai/rag-pipeline Last reviewed: 2026-08-02 ## Data model [#data-model] ```sql CREATE EXTENSION IF NOT EXISTS vector; CREATE TABLE documents ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, tenant_id bigint NOT NULL, source_uri text NOT NULL, source_version text NOT NULL, title text NOT NULL, access_scope text[] NOT NULL DEFAULT '{}', created_at timestamptz NOT NULL DEFAULT now(), UNIQUE (tenant_id, source_uri, source_version) ); CREATE TABLE document_chunks ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, document_id bigint NOT NULL REFERENCES documents(id) ON DELETE CASCADE, ordinal integer NOT NULL CHECK (ordinal >= 0), content text NOT NULL, token_count integer NOT NULL CHECK (token_count > 0), embedding vector(1536) NOT NULL, embedding_model text NOT NULL, search_vector tsvector GENERATED ALWAYS AS (to_tsvector('simple', content)) STORED, UNIQUE (document_id, ordinal) ); ``` ## Ingestion must be replayable [#ingestion-must-be-replayable] Store source version, chunker version, embedding model, and dimension. Derive deterministic document/chunk keys for idempotent upsert. When changing models, build a new embedding column or table and dual-write during rebuild; never mix incomparable vectors in one index. ## Retrieval order [#retrieval-order] 1. Filter tenant, permission, document state, and time in SQL. 2. Produce bounded candidates independently from full text and vectors. 3. Merge with rank fusion or application reranking. 4. Fetch a small number of neighboring chunks for continuity. 5. Return source URI, version, chunk id, and excerpt for citation. An illustrative vector candidate query: ```sql SELECT c.id, c.document_id, c.ordinal, c.content, c.embedding <=> $1::vector AS distance FROM document_chunks AS c JOIN documents AS d ON d.id = c.document_id WHERE d.tenant_id = $2 AND d.access_scope && $3::text[] ORDER BY c.embedding <=> $1::vector LIMIT 40; ``` Index type and parameters depend on scale, recall, latency, and write pattern. Establish an exact-search baseline before evaluating HNSW or IVFFlat; demo data is not enough. ### Approximate indexes and filters [#approximate-indexes-and-filters] HNSW/IVFFlat normally apply tenant, ACL, and other predicates after the index produces candidates, so a query can return fewer rows than its `LIMIT`. That is not a reason to weaken authorization filters. pgvector 0.8.0+ iterative scans can expand candidate scanning; large tenants may also justify partitions, partial indexes, or separate tables. Measure recall\@k in real tenant/ACL buckets for every design. See [Vector search in production](/en/docs/ai/vector-production) and the [official pgvector filtering guidance](https://github.com/pgvector/pgvector#filtering) for index DDL, parameters, and evaluation. ## Security and citation [#security-and-citation] Authorization predicates stay inside SQL/RLS so the database applies them before rows leave the boundary. Never return global candidates to the application and filter there; unauthorized text can leak through logs, caches, or model context. Final answers carry verifiable citations and report insufficient evidence when retrieval is weak. Nearby text can be stale, contradictory, or from the wrong tenant. RAG needs versions, permissions, source precedence, and answer evaluation—not only nearest neighbors. --- # Safe SQL guardrails Canonical URL: https://pg.edu.rich/en/docs/ai/safe-sql Last reviewed: 2026-08-02 ## The database role is the first boundary [#the-database-role-is-the-first-boundary] ```sql CREATE ROLE agent_reader LOGIN; GRANT CONNECT ON DATABASE commerce TO agent_reader; GRANT USAGE ON SCHEMA app TO agent_reader; GRANT SELECT ON ALL TABLES IN SCHEMA app TO agent_reader; ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app GRANT SELECT ON TABLES TO agent_reader; ALTER ROLE agent_reader SET default_transaction_read_only = on; ALTER ROLE agent_reader SET statement_timeout = '5s'; ALTER ROLE agent_reader SET lock_timeout = '1s'; ALTER ROLE agent_reader SET idle_in_transaction_session_timeout = '10s'; ``` Configure credentials through a secret manager or cloud identity integration, never migrations, prompts, or tool responses. Confirm the role cannot `SET ROLE` into a stronger role. ## Pre-execution policy [#pre-execution-policy] Validate generated SQL with a parser/AST, not regex. Default rules: * Allow one `SELECT` statement only. * Reject `COPY ... PROGRAM`, large objects, foreign-data wrappers, and dangerous functions. * Reject multiple statements and comment-based bypasses. * Restrict accessible schemas, tables, and columns. * Bind values; choose identifiers only from an allowlist. * Add a `LIMIT` to non-aggregate results and cap returned bytes in the driver. * A cost preflight with `EXPLAIN (FORMAT JSON)` is useful, but estimated cost is not a runtime guarantee. ## Use a read-only transaction for each read [#use-a-read-only-transaction-for-each-read] ```sql BEGIN READ ONLY; SET LOCAL statement_timeout = '5s'; SET LOCAL lock_timeout = '1s'; SET LOCAL search_path = app, pg_catalog; SELECT id, status, total_cents FROM orders WHERE customer_id = $1 ORDER BY placed_at DESC LIMIT 100; COMMIT; ``` Read-only transactions can still run expensive queries and expose readable data. Privilege, cost, and output bounds are all required. ## Do not expose arbitrary write SQL [#do-not-expose-arbitrary-write-sql] Prefer domain tools: ```json { "tool": "cancel_order", "arguments": { "order_id": 8842, "expected_status": "pending", "reason": "duplicate order", "idempotency_key": "case-2026-184" } } ``` The application validates identity and transition, runs parameterized SQL in a transaction, and returns a typed outcome. Bulk writes, DDL, `GRANT`, restore, and replication configuration should not be general-agent tools. ## Audit fields [#audit-fields] Record requester/tenant, tool, model and prompt versions, contract version, database target, parameter-redacted SQL fingerprint, risk tier, approver, row count, duration, SQLSTATE, and truncation state. Do not copy raw sensitive results into general logs. Writing first and noticing “too many rows” later may already fire triggers or external effects. Preview the target set in a controlled transaction, or make the domain API constrain the modifiable set in its predicate. --- # Schema retrieval and documentation Canonical URL: https://pg.edu.rich/en/docs/ai/schema-retrieval Last reviewed: 2026-08-02 ## Do not let the model explore production [#do-not-let-the-model-explore-production] A production agent should not have unbounded catalog exploration. A trusted build job extracts schema, redacts and versions it, and publishes it to retrieval. Runtime returns only a task-relevant subgraph. ## Tables and columns [#tables-and-columns] Use `information_schema` for portable basics: ```sql SELECT c.table_schema, c.table_name, c.ordinal_position, c.column_name, c.data_type, c.udt_name, c.is_nullable, c.column_default FROM information_schema.columns AS c WHERE c.table_schema = ANY($1::text[]) ORDER BY c.table_schema, c.table_name, c.ordinal_position; ``` Column comments come from PostgreSQL catalogs: ```sql SELECT n.nspname AS schema_name, cls.relname AS table_name, a.attname AS column_name, col_description(cls.oid, a.attnum) AS comment FROM pg_catalog.pg_attribute AS a JOIN pg_catalog.pg_class AS cls ON cls.oid = a.attrelid JOIN pg_catalog.pg_namespace AS n ON n.oid = cls.relnamespace WHERE n.nspname = ANY($1::text[]) AND cls.relkind IN ('r', 'p') AND a.attnum > 0 AND NOT a.attisdropped; ``` ## Foreign-key edges form the task graph [#foreign-key-edges-form-the-task-graph] ```sql SELECT src_ns.nspname AS table_schema, src.relname AS table_name, src_col.attname AS column_name, dst_ns.nspname AS foreign_table_schema, dst.relname AS foreign_table_name, dst_col.attname AS foreign_column_name FROM pg_catalog.pg_constraint AS con JOIN pg_catalog.pg_class AS src ON src.oid = con.conrelid JOIN pg_catalog.pg_namespace AS src_ns ON src_ns.oid = src.relnamespace JOIN pg_catalog.pg_class AS dst ON dst.oid = con.confrelid JOIN pg_catalog.pg_namespace AS dst_ns ON dst_ns.oid = dst.relnamespace CROSS JOIN LATERAL unnest(con.conkey, con.confkey) AS key_columns(src_attnum, dst_attnum) JOIN pg_catalog.pg_attribute AS src_col ON src_col.attrelid = src.oid AND src_col.attnum = key_columns.src_attnum JOIN pg_catalog.pg_attribute AS dst_col ON dst_col.attrelid = dst.oid AND dst_col.attnum = key_columns.dst_attnum WHERE con.contype = 'f' AND src_ns.nspname = ANY($1::text[]) ORDER BY con.oid, src_col.attnum; ``` `conkey` and `confkey` correspond positionally; parallel `unnest` preserves composite foreign-key column mappings. Joining `information_schema` views only by `constraint_name` can produce a Cartesian product of columns for a composite key. ## Documentation build flow [#documentation-build-flow] ```text merge migration → apply all migrations to an ephemeral database → extract catalogs → normalize ordering and remove environment values → generate JSON plus Markdown summaries → hash / bind migration version → review schema diff → publish to retrieval index ``` A table summary keeps purpose, primary and foreign keys, column types and nullability, constraints, business comments, sensitivity, and only the most important query indexes. Expand function bodies, view definitions, and policies on demand. ## Prevent staleness [#prevent-staleness] Every agent tool returns `contract_version`. If the runtime migration version differs from retrieval, reject high-risk requests and trigger a rebuild. Never silently use a stale contract. --- # Text-to-SQL production pattern Canonical URL: https://pg.edu.rich/en/docs/ai/text-to-sql Last reviewed: 2026-08-02 The goal of Text-to-SQL is not “produce something that runs.” It is to execute a correct query only when evidence, privilege, and cost boundaries are clear—and clarify or refuse everything else. ## Recommended execution chain [#recommended-execution-chain] ```text natural-language question → resolve business entities, metric, time range, and grain → retrieve a versioned schema/metric contract and a few verified examples → generate a structured query plan and parameters, not directly executed free text → validate SQL AST, object/function allowlists, privilege, and cost → restricted role + read-only transaction + timeouts + result bounds → return result, metric definition, SQL fingerprint, truncation, and explainable errors ``` Model context should include schema version, table/column semantics, keys, enums, time zone, currency units, soft-delete rules, tenant boundaries, approved metric definitions, and allowed objects. Do not indiscriminately inject all DDL, sample customer data, or credentials. ## Prefer structured tools [#prefer-structured-tools] For common analytics, have the model produce domain parameters: ```json { "metric": "paid_order_revenue", "time_range": { "start": "2026-07-01", "end": "2026-08-01" }, "group_by": ["day"], "filters": [{ "field": "region", "op": "eq", "value": "east" }], "limit": 100 } ``` The server maps metrics, fields, and operators to reviewed SQL. Only long-tail exploration enters a free-SQL lane, which must still parse an AST. A regex check for “starts with SELECT” is not a guardrail: CTEs, data-modifying CTEs, functions, `COPY`, multiple statements, and comment tricks defeat naive string checks. ## Database execution envelope [#database-execution-envelope] ```sql BEGIN READ ONLY; SET LOCAL statement_timeout = '3s'; SET LOCAL lock_timeout = '500ms'; SET LOCAL idle_in_transaction_session_timeout = '5s'; -- One policy-approved parameterized SELECT; server enforces row/byte bounds SELECT date_trunc('day', paid_at) AS day, sum(total_cents) AS revenue_cents FROM analytics.paid_orders WHERE tenant_id = $1 AND paid_at >= $2 AND paid_at < $3 GROUP BY 1 ORDER BY 1 LIMIT 100; COMMIT; ``` `READ ONLY` is defense in depth, not a complete sandbox. Allow only trusted functions and objects, execute as a dedicated low-privilege role, and bind tenant, environment, and parameters on the server. The model never supplies a connection string, role, or `search_path`. ## Pre-execution checks [#pre-execution-checks] 1. Allow one statement and approved AST nodes; reject DDL/DML, `COPY`, arbitrary functions, and administration objects. 2. Convert every value to a bound parameter; identifiers only come from the schema-contract allowlist. 3. Run `EXPLAIN (FORMAT JSON)` on expensive candidates and inspect objects, estimated rows, and total cost. Estimates are signals, not execution-time guarantees. 4. Require time ranges and row/byte/join bounds. Route bulk exports to a separate asynchronous product path. 5. Reject sensitive columns in policy or expose reviewed masked views; never rely on the model remembering not to select them. 6. Inject tenant scope through database RLS or server templates, never from the user's wording. ## Correctness and refusal [#correctness-and-refusal] A runnable query can still answer the wrong question. Evaluation sets should cover empty results, join duplication, time-zone boundaries, NULLs, refunds/cancellations, late data, tenant isolation, and ambiguous metrics. Assert the allow/refuse decision, result set, accessed objects, maximum cost, and explanation together. Clarify instead of guessing when a metric has multiple business definitions, a date lacks year/time zone, a name maps to multiple IDs, the request requires a nonexistent historical snapshot, or the schema contract does not match deployment. At most perform bounded regeneration from structured syntax errors. `57014` (cancel/timeout) should narrow the request or switch to async; retry `40001` and `40P01` only when the whole transaction is safe to replay. Retain the original request, schema version, query fingerprint, and final decision. Read the [PostgreSQL 18 `READ ONLY` transaction semantics](https://www.postgresql.org/docs/18/sql-set-transaction.html) and [SQLSTATE appendix](https://www.postgresql.org/docs/18/errcodes-appendix.html). --- # pgvector production practices Canonical URL: https://pg.edu.rich/en/docs/ai/vector-production Last reviewed: 2026-08-02 [pgvector](https://github.com/pgvector/pgvector) performs exact nearest-neighbor search by default. Search becomes approximate only after adding HNSW or IVFFlat. Index selection is an engineering tradeoff across recall, latency, memory, build time, and write cost. ## Fix distance semantics first [#fix-distance-semantics-first] | Meaning | Operator | Index operator class | | ----------------------------------------------- | -------- | -------------------- | | L2 / Euclidean distance | `<->` | `vector_l2_ops` | | Inner product (negative inner product returned) | `<#>` | `vector_ip_ops` | | Cosine distance | `<=>` | `vector_cosine_ops` | Embedding generation, index, and query must use the same distance meaning. Cosine similarity is `1 - cosine distance`. Store embedding model, dimension, normalization, and generation version; do not mix incomparable vectors in one column/index. ## Establish an exact baseline [#establish-an-exact-baseline] Sample the real query distribution and save exact top-k results. Compare approximate indexes on `recall@k`, p50/p95/p99 latency, insufficient-result rate, and resources—not one demonstration query. ```sql BEGIN; SET LOCAL enable_indexscan = off; SELECT c.id FROM document_chunks AS c JOIN documents AS d ON d.id = c.document_id WHERE d.tenant_id = $1 ORDER BY c.embedding <=> $2::vector LIMIT 20; ROLLBACK; ``` Disabling index scans is for baselines and diagnosis, not a production setting. Cover hot/cold tenants, common ACLs, time filters, new writes, deletions, and embedding-distribution drift. ## HNSW and IVFFlat [#hnsw-and-ivfflat] ```sql CREATE INDEX CONCURRENTLY document_chunks_embedding_hnsw ON document_chunks USING hnsw (embedding vector_cosine_ops); ``` * **HNSW** generally has a better query speed/recall tradeoff and needs no training set, but builds more slowly, uses more memory, and costs more to maintain. * **IVFFlat** builds faster and uses less memory, but needs representative existing data to form lists and generally has a weaker speed/recall tradeoff. Do not create it on an empty table and forget to rebuild. * On an existing production table, prefer `CREATE INDEX CONCURRENTLY` and observe WAL, disk, build duration, and replica lag. There is no universal `m`, `ef_construction`, `ef_search`, `lists`, or `probes` value. Start with defaults and an exact baseline, then tune against real filters. ## Filtering changes recall [#filtering-changes-recall] With approximate indexes, filters are normally applied after the index scan produces candidates. At the default `hnsw.ef_search = 40`, if only 10% of candidates satisfy tenant/ACL filters, the query can return fewer than its `LIMIT` even when more matching rows exist. pgvector 0.8.0+ supports iterative scans that continue when initial candidates are insufficient: ```sql BEGIN; SET LOCAL hnsw.iterative_scan = strict_order; SET LOCAL hnsw.ef_search = 200; SELECT c.id, c.content, c.embedding <=> $1::vector AS distance FROM document_chunks AS c JOIN documents AS d ON d.id = c.document_id WHERE d.tenant_id = $2 AND d.access_scope && $3::text[] ORDER BY c.embedding <=> $1::vector LIMIT 20; COMMIT; ``` Confirm the pgvector version offered by the cloud service. For a few skewed tenant values, consider list partitioning; for many values, partial indexes for large tenants, separate tables, or physical isolation may work better. Validate the choice with filtered recall and operational cost. Keep tenant/ACL predicates in SQL/RLS; never retrieve globally and filter in the application. Even when PostgreSQL correctly blocks unauthorized rows, a shared ANN graph may under-return after filtering. Security and recall are separate acceptance criteria. ## Launch bar [#launch-bar] * Every embedding version has replayable ingestion, an exact gold set, and rollback. * Record model version, filter bucket, candidate/result counts, distance distribution, latency, and truncation online. * Sample exact searches regularly to calculate recall\@k, bucketed by tenant/ACL. * Rebuild embeddings by dual-writing to a new column/table, building a new index, evaluating, then atomically switching reads. * Treat text and metadata as source of truth; vectors are rebuildable from versioned inputs. * Produce full-text and vector candidates independently, then fuse or rerank with a versioned method. Use the [pgvector README sections on indexing, filtering, and monitoring](https://github.com/pgvector/pgvector#hnsw) as the authoritative parameter reference. --- # Free PostgreSQL cloud database guide Canonical URL: https://pg.edu.rich/en/docs/cloud/free-postgresql Last reviewed: 2026-08-02 Classify free databases before comparing them: **managed services that run PostgreSQL**, **developer platforms built around PostgreSQL**, and **independent databases that implement pgwire or part of the SQL dialect**. A working driver connection does not prove extension, transaction, or operational compatibility. This page was checked against provider pages on 2026-08-02. Free limits, regions, project counts, sleep, and backup policies change quickly; reopen every source before creating a project. Free tiers generally carry no production SLA and do not replace an independent export and restore drill. ## Free PostgreSQL service comparison [#free-postgresql-service-comparison] | Service | Current free snapshot | Critical limit | Better fit | | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------ | | [Supabase](https://supabase.com/pricing) | Up to 2 active projects; 500 MB database per project; Free includes 1 GB file storage and 5 GB egress | Pauses after one inactive week; **no automatic backup or PITR** on Free | BaaS requiring Auth, Storage, Realtime, and APIs | | [Neon](https://neon.com/pricing) | Up to 100 projects; 0.5 GB storage and 100 CU-hours/month per project; 5 GB public transfer | Scales to zero after about 5 idle minutes; limited free restore window | PostgreSQL, branches, preview/CI databases, intermittent workloads | | [Aiven for PostgreSQL](https://aiven.io/docs/products/postgresql/concepts/pg-free-tier) | 1 CPU, 1 GB RAM, 1 GB disk, and backups | Single node, `max_connections=20`, no HA/SLA/VPC/pooler; idle services may power off | Traditional managed-PostgreSQL learning and small validation | | [Nhost](https://nhost.io/pricing) | 1 active project; 1 GB database, 1 GB file storage, and 5 GB egress | Pauses after one inactive week; GraphQL/Auth/Storage create platform coupling | GraphQL-first Hasura applications and an integrated backend | | [Prisma Postgres](https://www.prisma.io/pricing) | 500 MB storage, 100,000 operations/month, and up to 50 databases | Every SQL or Prisma query counts as an operation; Free is positioned for evaluation | Prisma workflows, temporary databases, PR and agent environments | | [Koyeb PostgreSQL](https://www.koyeb.com/docs/databases) | 0.25 vCPU, 1 GB RAM, and 1 GB data | Only 5 active compute hours/month; sleeps when idle | Demos, tutorials, and very infrequent tests, not a persistent API | | [Render Postgres](https://render.com/docs/free#free-postgres) | 1 GB and one free instance per workspace | Expires after 30 days; no backups or managed pooling before deletion | One-off demos and platform evaluation | These units are not interchangeable. Neon CU-hours, Prisma operations, Koyeb active hours, and fixed VM capacity measure different things. Model a real request pattern, then verify whether excess usage pauses, rejects, deletes, or starts billing. ## Why CockroachDB is separate [#why-cockroachdb-is-separate] [CockroachDB Cloud Basic](https://www.cockroachlabs.com/pricing/) currently includes 50 million Request Units and 10 GiB of storage per month, but CockroachDB is an independent distributed SQL database, not a PostgreSQL server. It supports pgwire and much PostgreSQL syntax while retaining differences around range types, FDWs, advisory locks, privileges, and transaction behavior. Use its [PostgreSQL compatibility matrix](https://www.cockroachlabs.com/docs/stable/postgresql-compatibility) as the boundary. Evaluate it independently for globally distributed transactions and multi-region resilience. Do not substitute it for real PostgreSQL when learning extensions, catalogs, WAL, or PostgreSQL operations. ## Direct selection guide [#direct-selection-guide] | Requirement | Evaluate first | Why | | -------------------------------------------- | --------------- | ----------------------------------------------------------------- | | Auth, Storage, Realtime, REST/GraphQL APIs | Supabase | A complete application backend surrounds PostgreSQL | | Branching, preview databases, scale-to-zero | Neon | Database lifecycle fits CI and short-lived environments | | Traditional managed PostgreSQL | Aiven | Resources and limits resemble a small single-node service | | GraphQL-first development | Nhost | PostgreSQL plus Hasura, Auth, and Storage | | Prisma workflow and many temporary databases | Prisma Postgres | Operation billing and Prisma/agent tooling are closely integrated | | Very short demo | Koyeb or Render | Their free limits rule them out as durable data sources | For Drizzle, node-postgres, Kysely, and other ordinary PostgreSQL clients, separately test direct and pooled URLs, prepared statements, migrations, and transaction-pooling behavior on Neon, Supabase, Aiven, Nhost, and Prisma Postgres. A standard connection string is not proof of identical behavior. ## Pre-deployment free-tier checks [#pre-deployment-free-tier-checks] ```sql SELECT version(), current_setting('server_version_num') AS server_version_num, current_database(), current_user; SELECT extname, extversion FROM pg_extension ORDER BY extname; SHOW max_connections; SHOW transaction_read_only; ``` Then verify: 1. PostgreSQL major/minor and exact extension versions; 2. direct and pooled connection purpose, limit, and pool mode; 3. cold start after idle and whether DNS or endpoints change; 4. automatic backup, PITR, retention, and whether Free includes them; 5. egress and operation/CU-hour accounting plus hard limits; 6. `pg_dump` export, restore into local PostgreSQL, and the retrieval window after pause or deletion; 7. whether paid upgrade is in place or requires migration and connection-string changes. Important production systems need measurable RPO/RTO, backup retention, a restore path, support, and incident notification. Even on a paid managed service, perform one off-platform export and independent restore. Use the [cloud production selection checklist](/en/docs/cloud/production-checklist) for production and exit costs, and [PostgreSQL lineage and compatible databases](/en/docs/reference/postgresql-compatible-databases) for engine boundaries. --- # Cloud PostgreSQL entry point Canonical URL: https://pg.edu.rich/en/docs/cloud Last reviewed: 2026-08-02 “Cloud PostgreSQL” is not one product category. Classify the service first to understand which PostgreSQL assumptions remain valid: | Category | Examples | Compatibility boundary | Best fit | | ------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | Managed community PostgreSQL | Amazon RDS for PostgreSQL, Cloud SQL, Azure Database for PostgreSQL, Alibaba Cloud RDS, TencentDB | Runs a community engine, while host access, parameters, extensions, and upgrades are platform-controlled | Preserve strong SQL/tool compatibility while delegating patching, backup, and HA | | PostgreSQL-compatible enhanced engine | Aurora PostgreSQL-Compatible, AlloyDB | Protocol and broad SQL compatibility; vendor implements storage, replication, release cadence, and some behavior | Trade some portability for elasticity, read scaling, or analytical/AI features | | Developer data platform | Neon, Supabase | PostgreSQL is central, with platform-specific connection, branching, auth, API, realtime, or suspend semantics | Fast delivery, preview environments, small operations teams, or full-stack products | A successful driver connection only proves wire-protocol compatibility. Validate extension versions, parameters, catalog views, replication, poolers, backup export, maintenance restarts, and failover behavior before launch. ## Ownership boundary [#ownership-boundary] Managed services commonly own infrastructure, patch orchestration, automated backups, and some failover. The application team still owns: * schemas, constraints, indexes, SQL, and transaction design; * connection budgets, pooling mode, and retry policy; * explicit RPO/RTO and real restore drills; * data access, keys, networking, and least privilege; * slow queries, bloat, long transactions, vacuum, and cost controls; * major-version upgrades, extension upgrades, and an exit plan. AWS explicitly identifies query tuning as the customer's responsibility for Aurora—a useful starting model for every managed database. See the [Amazon Aurora overview](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_AuroraOverview.html). ## Recommended decision order [#recommended-decision-order] 1. State residency, compliance, RPO, RTO, peak connections, latency, and budget limits. 2. Confirm the required PostgreSQL major version and the **exact versions** of extensions. 3. Benchmark representative data and SQL; do not substitute vendor headline numbers. 4. Exercise maintenance, failover, PITR, connection exhaustion, and regional failure. 5. Export with native tools and restore into an independent PostgreSQL environment once. Facts in this section were checked on **2026-08-02**. Cloud features, regions, and plans change quickly; re-check official documentation during procurement and launch. --- # Cloud PG production checklist Canonical URL: https://pg.edu.rich/en/docs/cloud/production-checklist Last reviewed: 2026-08-02 ## 1. Compatibility inventory [#1-compatibility-inventory] * What are the PostgreSQL major version, patch cadence, and end-of-support date? * Are every required extension and its exact version present in `pg_extension`? Is upgrade automatic, manual, or migration-based? * Which settings are immutable? Is `shared_preload_libraries` available? * Are logical replication, slots, FDWs, event triggers, and required authentication supported? * Which catalog, statistics, and superuser operations have platform-specific replacements? * Have drivers, ORM, migrations, and backup tools passed the real delivery pipeline? Store the answers as a machine-readable manifest bound to service SKU, region, engine version, and verification date. ## 2. Availability and recovery [#2-availability-and-recovery] | Exercise | Example acceptance condition | | ------------------- | ------------------------------------------------------------------------------------------------------------ | | Forced failover | Clients reconnect inside budget; failed transactions return recognizable SQLSTATE; no silent partial success | | PITR | Restore a new instance to the target time; verify rows, constraints, roles, and extensions; measure RTO | | Accidental deletion | Document separate whole-instance, database, and table-level paths and durations | | Region failure | DNS, keys, object-storage backups, and application compute do not share the database failure domain | | Backup export | Restore a usable copy outside the provider account | Applications need connection timeouts, transaction-level retries, and idempotency keys. Do not replay a write that may have committed unless a business idempotency key can confirm the outcome. ## 3. Connections and elasticity [#3-connections-and-elasticity] Budget connections across every application replica, worker, migration tool, BI client, and agent. Prefer a controlled pool for serverless/agent traffic, while confirming: * whether transaction pooling supports session state, temporary tables, LISTEN/NOTIFY, or prepared statements; * whether scale-down, suspend, or failover changes endpoints or TLS certificates; * which of `statement_timeout`, `idle_in_transaction_session_timeout`, and client timeouts fires first; * whether bursts queue in the application instead of becoming a direct PostgreSQL connection storm. ## 4. Cost model [#4-cost-model] Beyond compute and storage, estimate IOPS, backups, cross-zone/region traffic, replicas, logs, monitoring, proxies, PITR, snapshot export, and support. For AI, separate embedding, index rebuild, vector storage, retrieval, and reranking costs. ## 5. Portability [#5-portability] Quarterly—or before a major upgrade—run: ```bash pg_dump --format=custom --no-owner --no-acl "$DATABASE_URL" > app.dump createdb portability_restore pg_restore --exit-on-error --no-owner --no-acl \ --dbname=portability_restore app.dump ``` This checks logical portability; it does not replace provider PITR. After restore, verify extensions, roles/grants, large objects, sequences, row counts, constraints, critical results, and query plans. ## Launch evidence pack [#launch-evidence-pack] * service, region, SKU, engine, and extension version manifest; * RPO, RTO, connection budget, and capacity model; * failover, PITR, accidental-delete, and off-platform restore reports; * encryption, network, role, RLS, and key-rotation records; * engine/extension upgrade and provider-exit runbooks; * latency, error, WAL, vacuum, storage, and cost data under representative load. --- # Cloud PostgreSQL service map Canonical URL: https://pg.edu.rich/en/docs/cloud/service-map Last reviewed: 2026-08-02 ## Managed community PostgreSQL [#managed-community-postgresql] | Service | Verified capabilities | Validate during selection | | ----------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | [Amazon RDS for PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html) | Automated backup/PITR, Multi-AZ, read replicas, VPC, and TLS | No host access; parameters, privileged capabilities, and extensions come from platform allowlists | | [Cloud SQL for PostgreSQL](https://docs.cloud.google.com/sql/docs/postgres/introduction) | Managed backup, HA/failover, encryption, private/public networking, replicas, and maintenance | Maintenance or configuration may restart instances; check regional, extension, connection, and AI-feature availability | | [Azure Database for PostgreSQL Flexible Server](https://learn.microsoft.com/en-us/azure/postgresql/overview) | Same-zone/zone-redundant HA, PITR, TLS, private networking, managed maintenance, optional built-in PgBouncer | Automated backup retention defaults to 7 days and extends to 35; built-in PgBouncer uses port 6432, so verify pooling mode | | [Alibaba Cloud RDS for PostgreSQL](https://help.aliyun.com/en/rds/apsaradb-rds-for-postgresql/what-is-apsaradb-rds-for-postgresql/) | Basic, High-availability, and Cluster editions; automated/manual backup, read-only instances, and proxy options | HA standbys are not directly readable; sync mode, proxy routing, and backup type vary by architecture | | [TencentDB for PostgreSQL](https://www.tencentcloud.com/document/product/409) | Managed installation, storage, HA, backup, major/minor upgrades, and read-only groups | Official guidance says one read-only instance has no HA/SLA; validate node count, routing, and consistency for production read groups | Cloud providers do not necessarily ship the same engine or extension on the day the community does. Split “supports PostgreSQL 17/18” into three checks: can a new instance use it, can an existing instance upgrade to it, and does the required extension support it? ## PostgreSQL-compatible enhanced engines [#postgresql-compatible-enhanced-engines] | Service | Architecture | Difference to accept | | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Aurora PostgreSQL-Compatible](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_AuroraOverview.html) | Customized PostgreSQL-compatible engine and distributed storage, managed primarily as clusters | Aurora has its own release cadence; extensions come from a [support matrix](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraPostgreSQLReleaseNotes/AuroraPostgreSQL.Extensions.html) and do not automatically upgrade with the community extension | | [AlloyDB for PostgreSQL](https://docs.cloud.google.com/alloydb/docs/overview) | Decoupled compute/storage, cross-zone HA, optional columnar engine, vector and model integrations | Not community-binary-equivalent; validate extensions, parameters, migration tools, analytical paths, and regional capability | “PostgreSQL-compatible” describes a migration starting point, not a test result. Exercise schema migration, critical queries, transactional concurrency, drivers, extensions, and recovery. ## Developer data platforms [#developer-data-platforms] | Service | Strength | Often-missed production concern | | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | [Neon](https://neon.com/docs/get-started/why-neon) | Separated compute/storage, autoscaling, scale-to-zero, database branching, and pooled connections | Cold starts, changing compute size, branch data governance, and the different purposes of pooled versus direct connections | | [Supabase](https://supabase.com/docs/guides/database/overview) | A full PostgreSQL database per project plus Auth, Storage, Realtime, APIs, and Supavisor | Design RLS correctly before browser-facing data APIs; verify backup/PITR plan, connection budget, and coupling to platform components | For no-cost development environments, use the [free PostgreSQL cloud database guide](/en/docs/cloud/free-postgresql), checked on 2026-08-02. Supabase, Neon, Nhost, and Prisma Postgres have different platform structures and should not be ranked by free storage alone. Validate recovery granularity, retention, cross-region copies, key dependencies, exportability, and measured restore time. Managed physical backups on platforms such as Azure cannot be exported directly; an exit path usually needs `pg_dump`, logical replication, or a migration service. ## For AI workloads [#for-ai-workloads] When choosing cloud PG for RAG or agent metadata, check: 1. the **exact pgvector version**, HNSW/IVFFlat support, and upgrade cadence; 2. connection limits and pooling for short-lived functions and agents; 3. memory, temporary storage, WAL, and replica lag during vector-index builds; 4. real recall after tenant/ACL filtering, not an unfiltered benchmark; 5. whether the embedding model, vector data, and database share the required residency boundary; 6. whether text, metadata, and embeddings can be exported without pipeline lock-in. Provider model endpoints, automated embedding, or AI assistants can remove glue code, but add privilege, region, model-lifecycle, and cost dimensions. They do not replace database RLS, least-privilege roles, or retrieval evaluation. If a candidate only supports the PostgreSQL protocol or reuses its query layer, continue with [PostgreSQL lineage and compatible databases](/en/docs/reference/postgresql-compatible-databases). --- # Data modeling and constraints Canonical URL: https://pg.edu.rich/en/docs/core/data-modeling Last reviewed: 2026-08-02 A good PostgreSQL model does not postpone every rule to application code. It teaches the database which states are valid. ## A working order model [#a-working-order-model] ```sql CREATE TABLE customers ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, email text NOT NULL, display_name text NOT NULL CHECK (length(trim(display_name)) > 0), created_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT customers_email_unique UNIQUE (email) ); CREATE TABLE orders ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, customer_id bigint NOT NULL REFERENCES customers(id), status text NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'paid', 'shipped', 'cancelled')), total_cents bigint NOT NULL CHECK (total_cents >= 0), placed_at timestamptz NOT NULL DEFAULT now() ); COMMENT ON COLUMN orders.total_cents IS 'Order total in the smallest currency unit; never a floating-point amount.'; ``` ## Type choices [#type-choices] | Need | Prefer | Avoid | | ------------------- | -------------------------------------------------------------- | --------------------------------------------------- | | Primary key | `bigint GENERATED ... AS IDENTITY` or `uuid` | New designs depending on implicit `serial` behavior | | Money | Smallest unit in `bigint`, or explicit `numeric(p,s)` | `real` / `double precision` | | Instant | `timestamptz` | Storing a real-world instant as text | | Text | `text` plus business constraints | Arbitrary `varchar(255)` without meaning | | State | `CHECK` for small stable sets; reference table for a lifecycle | Unconstrained free text | | Document attributes | `jsonb` | Hiding core relations and foreign keys in JSON | `timestamptz` stores an absolute instant and renders it in the session time zone. It does not retain the input zone name. Store a zone identifier separately when rules such as `Europe/Paris` matter. ## What constraints mean [#what-constraints-mean] * `NOT NULL`: a value must exist. * `CHECK`: each row must satisfy a predicate. * `UNIQUE`: a candidate key is unique; multiple `NULL`s are allowed by default. * `PRIMARY KEY`: unique, non-null row identity. * `FOREIGN KEY`: the target must exist; deletion behavior is a design decision. `ON DELETE CASCADE` says children should disappear with the parent. Use it only for truly dependent lifecycles. Invoices and audit records normally should not cascade. ## Schemas and names [#schemas-and-names] Use an explicit schema for application objects and reduce default privilege: ```sql CREATE SCHEMA app; REVOKE CREATE ON SCHEMA public FROM PUBLIC; ALTER ROLE app_runtime SET search_path = app, pg_catalog; ``` Names that help both humans and models are complete, stable, and low on abbreviations: `customer_id` beats `cid`; `created_at` beats `ctime`. Use `COMMENT ON` for units, state transitions, and sensitivity—not to repeat the column name. ## Verify the model [#verify-the-model] ```sql INSERT INTO customers (email, display_name) VALUES ('ada@example.com', 'Ada') RETURNING id, created_at; -- Expected to fail: totals cannot be negative INSERT INTO orders (customer_id, total_cents) VALUES (1, -100); ``` A model is not verified merely because valid rows work. Representative invalid rows must fail for the intended reason. --- # Indexes and EXPLAIN Canonical URL: https://pg.edu.rich/en/docs/core/indexes-explain Last reviewed: 2026-08-02 ## Capture the plan first [#capture-the-plan-first] ```sql EXPLAIN (ANALYZE, BUFFERS, VERBOSE) SELECT id, customer_id, placed_at FROM orders WHERE customer_id = 42 ORDER BY placed_at DESC LIMIT 20; ``` * `EXPLAIN` shows estimates without executing. * `ANALYZE` executes and reports actual rows and timing. Wrap writes in a transaction and roll back. * `BUFFERS` reports shared/local/temp block hits and reads. * Compare estimated `rows` with `actual rows`, loop counts, expensive nodes, and disk sorts. `EXPLAIN ANALYZE DELETE ...` really deletes. Inspect a write with `BEGIN; EXPLAIN (ANALYZE, BUFFERS) ...; ROLLBACK;` only after confirming there are no non-transactional external effects. ## Index the query shape [#index-the-query-shape] The filter and ordering above can use: ```sql CREATE INDEX CONCURRENTLY orders_customer_placed_idx ON orders (customer_id, placed_at DESC) INCLUDE (id); ``` A multicolumn B-tree normally matches from its left side. Actual predicates, range conditions, and ordering determine column order—not a simplistic “most selective first” rule. `INCLUDE` columns do not participate in search ordering but may enable an index-only scan. The visibility map still determines whether heap access is avoidable. ## Common index types [#common-index-types] | Type | Fits | | --------------- | ------------------------------------------------------------------------------------------------------------------------- | | B-tree | Equality, ranges, ordering; the default | | GIN | `jsonb` containment, arrays, full-text search | | GiST | Geometry, ranges, and extension operators | | SP-GiST | Tries, quadtrees, k-d trees, and other partitioned search spaces | | BRIN | Huge tables whose physical order correlates with values, such as append-only time data | | Hash | Equality only; B-tree is usually more versatile | | Bloom extension | Equality across arbitrary combinations of many columns; lossy and rechecked; bundled classes only cover `int4` and `text` | These labels still do not prove an index is usable: the operator class determines exact operators and data types. See [index and storage access methods](/en/docs/reference/index-access-methods) for table access methods, HNSW/IVFFlat, and the full selection map. ## Two high-value patterns [#two-high-value-patterns] A partial index covers only relevant rows: ```sql CREATE INDEX orders_unfinished_idx ON orders (placed_at) WHERE status IN ('pending', 'paid'); ``` An expression index accelerates normalized lookup: ```sql CREATE UNIQUE INDEX customers_email_ci_idx ON customers (lower(email)); ``` The query predicate must match the expression or imply the partial condition for the planner to use it. ## Why an index is not used [#why-an-index-is-not-used] * The table is small and a sequential scan is cheaper. * The query returns a large fraction of rows. * Statistics are stale or miss cross-column correlation. * A function or implicit cast does not match the index expression. * The leftmost prefix of a multicolumn index is not usable. * Cost parameters do not reflect the storage system. Run `ANALYZE orders;` and inspect estimate errors before disabling sequential scans. ## Production creation and cleanup [#production-creation-and-cleanup] `CREATE INDEX CONCURRENTLY` reduces write blocking but takes longer, cannot run in a transaction block, and can leave an invalid index after failure. Inspect with: ```sql SELECT indexrelid::regclass, indisvalid, indisready FROM pg_index WHERE indrelid = 'orders'::regclass; ``` Every index adds write amplification, WAL, cache pressure, and vacuum work. Review unused indexes with `pg_stat_user_indexes` over a representative business cycle. --- # JSONB, full-text, and semantic retrieval Canonical URL: https://pg.edu.rich/en/docs/core/jsonb-search Last reviewed: 2026-08-02 PostgreSQL can hold relational data and JSON documents, perform lexical full-text search, and add vector retrieval through an extension. Co-location does not mean every concern belongs in one column. ## When JSONB fits [#when-jsonb-fits] Good fits: metadata from heterogeneous sources, optional attributes that change infrequently, and integration payloads that must preserve their original shape. Poor fits: primary and foreign keys, money, authorization boundaries, and core fields used constantly for joins, ordering, or aggregation. ```sql CREATE TABLE products ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, sku text NOT NULL UNIQUE, name text NOT NULL, attributes jsonb NOT NULL DEFAULT '{}'::jsonb, CHECK (jsonb_typeof(attributes) = 'object') ); INSERT INTO products (sku, name, attributes) VALUES ('KB-01', 'Keyboard', '{"layout":"75%","wireless":true}'); SELECT id, name FROM products WHERE attributes @> '{"wireless":true}'; ``` ## JSONB indexes [#jsonb-indexes] ```sql CREATE INDEX products_attributes_gin ON products USING gin (attributes); ``` The default GIN operator class supports several key and containment operations. If the workload is almost entirely `@>`, `jsonb_path_ops` is often smaller but supports a narrower operator set. Compare with real queries and distributions. A frequently queried attribute can use an expression index—or graduate into a normal column: ```sql CREATE INDEX products_layout_idx ON products ((attributes ->> 'layout')); ``` ## Built-in full-text search [#built-in-full-text-search] ```sql ALTER TABLE products ADD COLUMN search_document tsvector GENERATED ALWAYS AS ( setweight(to_tsvector('simple', coalesce(name, '')), 'A') || setweight(to_tsvector('simple', coalesce(attributes::text, '')), 'B') ) STORED; CREATE INDEX products_search_gin ON products USING gin (search_document); SELECT id, name, ts_rank(search_document, websearch_to_tsquery('simple', $1)) AS rank FROM products WHERE search_document @@ websearch_to_tsquery('simple', $1) ORDER BY rank DESC LIMIT 20; ``` The built-in `simple` configuration does not fully solve Chinese tokenization. Production Chinese search needs a dedicated segmentation extension, application-side tokenization, or an external search system. ## Semantic retrieval with pgvector [#semantic-retrieval-with-pgvector] Vectors are not a PostgreSQL core type. A common approach is the independent `pgvector` extension: ```sql CREATE EXTENSION IF NOT EXISTS vector; CREATE TABLE document_chunks ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, document_id bigint NOT NULL, content text NOT NULL, embedding vector(1536) NOT NULL, embedding_model text NOT NULL ); ``` Dimensions must match the model. Do not mix incomparable embedding models in one index. Store model name, chunking version, and source location so retrieval can be rebuilt and audited. Reduce candidates with keywords, permissions, tenant, and time filters before vector ranking. Enforce access filters in SQL; never rely on the model to remember them. Start with [Install pgvector](/en/docs/ai/pgvector-setup) for a working environment, then read [pgvector production practices](/en/docs/ai/vector-production) before adding approximate indexes. --- # Diagnose PostgreSQL lock waits and deadlocks Canonical URL: https://pg.edu.rich/en/docs/core/locks-deadlocks Last reviewed: 2026-08-02 ## Lock wait versus deadlock [#lock-wait-versus-deadlock] * **Lock wait**: a session waits for another transaction to release a conflicting lock; it may eventually succeed or time out. * **Deadlock**: sessions form a wait cycle and none can progress; PostgreSQL detects it and aborts one transaction. The deadlock SQLSTATE is `40P01`. The transaction must roll back; perform a bounded retry only when the entire business transaction is safe to replay. ## Inspect the blocking graph [#inspect-the-blocking-graph] ```sql SELECT blocked.pid AS blocked_pid, blocker.pid AS blocker_pid, now() - blocked.query_start AS blocked_for, blocked.wait_event_type, blocked.wait_event, left(blocked.query, 120) AS blocked_query, left(blocker.query, 120) AS blocker_query FROM pg_stat_activity AS blocked CROSS JOIN LATERAL unnest(pg_blocking_pids(blocked.pid)) AS b(pid) JOIN pg_stat_activity AS blocker ON blocker.pid = b.pid ORDER BY blocked.query_start; ``` Check whether the blocker is `idle in transaction`, what it changed, and whether the application is alive. Do not terminate a PID on sight. ## Reduce deadlocks [#reduce-deadlocks] 1. Lock resources in the same order on every code path, such as ascending account id. 2. Keep only database work that must be atomic inside the transaction; exclude user input and external APIs. 3. Index predicates used to locate rows for update, reducing scan and lock scope. 4. Chunk bulk work and keep concurrent workers out of overlapping key ranges. 5. Set evidence-based `lock_timeout` and `statement_timeout` values. ```sql BEGIN; SET LOCAL lock_timeout = '1s'; SET LOCAL statement_timeout = '10s'; SELECT id FROM accounts WHERE id = ANY($1::bigint[]) ORDER BY id FOR UPDATE; -- bounded writes COMMIT; ``` ## Before terminating a session [#before-terminating-a-session] `pg_cancel_backend(pid)` requests cancellation of the current statement. `pg_terminate_backend(pid)` ends the session and rolls back its transaction. Confirm that: * the PID still belongs to the target session, not an old screenshot; * rollback may take time and generate additional I/O; * the application will not reconnect and repeat the same blocker immediately; * interrupted work is retryable or has a business compensation path. See [PostgreSQL 18 explicit locking](https://www.postgresql.org/docs/18/explicit-locking.html) for lock modes and the conflict matrix. --- # PostgreSQL MVCC and snapshot visibility Canonical URL: https://pg.edu.rich/en/docs/core/mvcc-snapshots Last reviewed: 2026-08-02 MVCC (multi-version concurrency control) lets ordinary reads avoid blocking writes. An `UPDATE` does not overwrite the value in place for every reader; it creates a new row version, and each query uses its snapshot to decide which version is visible. ## Observe snapshots in two sessions [#observe-snapshots-in-two-sessions] Prepare data: ```sql CREATE TABLE mvcc_demo ( id integer PRIMARY KEY, value text NOT NULL ); INSERT INTO mvcc_demo VALUES (1, 'before'); ``` Session A: ```sql BEGIN ISOLATION LEVEL REPEATABLE READ; SELECT value FROM mvcc_demo WHERE id = 1; -- before ``` Session B: ```sql UPDATE mvcc_demo SET value = 'after' WHERE id = 1; COMMIT; ``` Back in session A: ```sql SELECT value FROM mvcc_demo WHERE id = 1; -- still before COMMIT; SELECT value FROM mvcc_demo WHERE id = 1; -- after ``` At `READ COMMITTED`, each statement gets a new snapshot, so a second query in the same transaction can observe session B's committed value. ## Why long transactions hurt [#why-long-transactions-hurt] While an old snapshot can still see row versions, vacuum cannot treat them as fully reclaimable. Long transactions therefore increase: * dead tuples and table/index bloat; * vacuum work and disk use; * retention pressure from slots, logical decoding, or standbys; * the risk window around transaction ID wraparound. Find sessions holding old transactions or snapshots: ```sql SELECT pid, usename, application_name, state, now() - xact_start AS transaction_age, age(backend_xmin) AS snapshot_xid_age, wait_event_type, wait_event, left(query, 120) AS query FROM pg_stat_activity WHERE xact_start IS NOT NULL OR backend_xmin IS NOT NULL ORDER BY xact_start NULLS LAST; ``` Do not terminate a session merely because it is old. Confirm workload purpose, backup/maintenance activity, retry safety, and termination impact. Row versions solve read visibility. Write conflicts, DDL, foreign-key checks, and explicit locks can still wait. Continue with [lock waits and deadlocks](/en/docs/core/locks-deadlocks). Use [PostgreSQL 18 concurrency control](https://www.postgresql.org/docs/18/mvcc.html) and [transaction isolation](https://www.postgresql.org/docs/18/transaction-iso.html) as authoritative references. --- # Query toolbox Canonical URL: https://pg.edu.rich/en/docs/core/queries Last reviewed: 2026-08-02 ## Shape of a maintainable query [#shape-of-a-maintainable-query] ```sql SELECT o.id, c.email, o.total_cents, o.placed_at FROM orders AS o JOIN customers AS c ON c.id = o.customer_id WHERE o.status = $1 AND o.placed_at >= $2 ORDER BY o.placed_at DESC, o.id DESC LIMIT $3; ``` This query specifies output, join condition, parameters, deterministic ordering, and a bound. The driver binds `$1`, `$2`, and `$3`; never concatenate user input into SQL. ## Choosing a join form [#choosing-a-join-form] | Goal | Use | | ---------------------------------- | ------------------------------------------------- | | Keep matching rows from both sides | `INNER JOIN` / `JOIN` | | Keep every row on the left | `LEFT JOIN` | | Test whether a related row exists | `EXISTS`, often clearer than join-plus-`DISTINCT` | | Find rows without a relation | `NOT EXISTS`, avoiding `NOT IN` null traps | ```sql SELECT c.id, c.email FROM customers AS c WHERE NOT EXISTS ( SELECT 1 FROM orders AS o WHERE o.customer_id = c.id ); ``` ## Aggregates and windows differ [#aggregates-and-windows-differ] `GROUP BY` collapses rows. Window functions retain detail rows while calculating across a window. ```sql SELECT customer_id, id AS order_id, total_cents, row_number() OVER ( PARTITION BY customer_id ORDER BY placed_at DESC, id DESC ) AS recency_rank, sum(total_cents) OVER (PARTITION BY customer_id) AS lifetime_cents FROM orders; ``` ## What CTEs are for [#what-ctes-are-for] A CTE names a stage in a complex query; it is not an automatic optimization switch. ```sql WITH recent_paid AS ( SELECT customer_id, total_cents FROM orders WHERE status = 'paid' AND placed_at >= now() - interval '30 days' ) SELECT customer_id, sum(total_cents) AS paid_cents FROM recent_paid GROUP BY customer_id; ``` ## Pagination [#pagination] Prefer keyset pagination for large result sets: ```sql SELECT id, placed_at, total_cents FROM orders WHERE (placed_at, id) < ($1, $2) ORDER BY placed_at DESC, id DESC LIMIT 50; ``` Unlike a large `OFFSET`, this does not repeatedly skip earlier rows and behaves more predictably under concurrent inserts. The cursor must contain every ordering key. ## Pre-flight checklist [#pre-flight-checklist] * Is the output contract explicit and minimal? * Can any join multiply rows? * Is `NULL` semantics intentional? * Does ordering have a unique final tie-breaker? * Does the driver bind every input value? * Do you need statement timeout and a result limit? --- # Transactions, MVCC, and concurrency Canonical URL: https://pg.edu.rich/en/docs/core/transactions Last reviewed: 2026-08-02 ## A minimal transaction [#a-minimal-transaction] ```sql BEGIN; SELECT balance_cents FROM accounts WHERE id = $1 FOR UPDATE; UPDATE accounts SET balance_cents = balance_cents - $2 WHERE id = $1 AND balance_cents >= $2; COMMIT; ``` A transaction makes several statements one atomic unit. `FOR UPDATE` locks selected rows until commit or rollback; the application must still inspect the update count. ## MVCC intuition [#mvcc-intuition] Multi-version concurrency control means readers normally do not block writers and writers normally do not block ordinary readers. Updates create new row versions. Autovacuum can reclaim old versions after no active snapshot can see them. Long transactions delay that cleanup and increase bloat, WAL retention, and replication-lag risk. Never hold a transaction open across user think time, network retries, or unrelated external API calls. ## Isolation levels [#isolation-levels] | Level | PostgreSQL behavior | Application duty | | ----------------- | -------------------------------------------------------------- | -------------------------------------------------------- | | `READ COMMITTED` | Default; each statement gets a fresh snapshot | Do not assume two reads in one transaction are identical | | `REPEATABLE READ` | Stable transaction snapshot; serialization failure is possible | Retry the whole transaction on `40001` | | `SERIALIZABLE` | Commits only outcomes proven equivalent to serial execution | Implement bounded whole-transaction retry and backoff | PostgreSQL treats `READ UNCOMMITTED` as `READ COMMITTED`. Beyond the SQL standard's minimum, PostgreSQL `REPEATABLE READ` also prevents phantom reads, but serialization failures can still require a whole-transaction retry. Sequence changes such as `nextval()` are not rolled back, so gaps are normal. ## Correct retry boundary [#correct-retry-boundary] After serialization failure or deadlock, the current transaction cannot continue. Roll it back and replay the **whole transaction**, not just the final SQL statement. ```text begin run all reads and writes commit on SQLSTATE 40001 or 40P01 rollback retry whole unit with bounded exponential backoff ``` External effects inside the retry boundary must be idempotent. A transactional outbox is often safer for post-commit work. ## Deadlocks and waits [#deadlocks-and-waits] Reduce deadlocks by locking resources in a consistent order, keeping transactions short, indexing lookup predicates, and setting appropriate `lock_timeout` and `statement_timeout` values. ```sql SET LOCAL lock_timeout = '2s'; SET LOCAL statement_timeout = '10s'; ``` `SET LOCAL` applies only to the current transaction. A client that begins and never ends a transaction retains a snapshot and perhaps locks. Monitor `pg_stat_activity.state = 'idle in transaction'` and consider `idle_in_transaction_session_timeout`. Use the [PostgreSQL 18 transaction-isolation documentation](https://www.postgresql.org/docs/18/transaction-iso.html) as the authoritative behavior reference. Continue with [MVCC and snapshot visibility](/en/docs/core/mvcc-snapshots) for old row versions and long transactions, then [lock waits and deadlocks](/en/docs/core/locks-deadlocks) for blocking diagnostics and safe intervention. --- # PostgreSQL autovacuum and table bloat Canonical URL: https://pg.edu.rich/en/docs/operations/autovacuum-bloat Last reviewed: 2026-08-02 Standard `VACUUM` does more than “free space”: it makes dead row versions reusable, maintains planner statistics and the visibility map, and prevents transaction ID/multixact wraparound. Most systems should leave autovacuum enabled. ## Routine observation [#routine-observation] ```sql SELECT schemaname, relname, n_live_tup, n_dead_tup, last_vacuum, last_autovacuum, vacuum_count, autovacuum_count, last_analyze, last_autoanalyze FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 30; ``` Statistics are estimates and can reset, so one `n_dead_tup` threshold cannot prove bloat. Combine table size, update rate, query latency, autovacuum logs, and trends. Inspect active vacuum work: ```sql SELECT pid, datname, relid::regclass AS relation, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, dead_tuple_bytes, num_dead_item_ids, indexes_total, indexes_processed FROM pg_stat_progress_vacuum; ``` These column names target PostgreSQL 18. Older majors can expose a different progress-view shape, so version-portable monitoring should inspect the target catalog first. ## Why it does not trigger or keep up [#why-it-does-not-trigger-or-keep-up] * a large table makes the default scale factor translate into too many changed rows; * workers, I/O capacity, or maintenance memory are insufficient; * long transactions, prepared transactions, slots, or standby snapshots block reclamation; * conflicting locks repeatedly cancel vacuum; * sustained writes exceed cleanup capacity. Override a measured hot table before making aggressive global changes: ```sql ALTER TABLE app.events SET ( autovacuum_vacuum_scale_factor = 0.02, autovacuum_vacuum_threshold = 1000, autovacuum_analyze_scale_factor = 0.01 ); ``` These are examples, not universal values. Calculate expected trigger frequency from table size and daily changes, then observe I/O, WAL, latency, and completion time. ## Manual maintenance boundary [#manual-maintenance-boundary] ```sql VACUUM (ANALYZE, VERBOSE) app.events; ``` Plain `VACUUM` mainly makes space reusable inside the relation and normally does not shrink the file back to the operating system. `VACUUM FULL` rewrites the table, needs extra disk, and takes `ACCESS EXCLUSIVE`; it is not routine cleanup. Identify the table, phase, wait event, and resource bottleneck first. Disabling autovacuum accumulates dead tuples, stale statistics, and freeze risk; anti-wraparound vacuum can run even when table-level autovacuum is disabled. Read [PostgreSQL 18 Routine Vacuuming](https://www.postgresql.org/docs/18/routine-vacuuming.html) for normative behavior. --- # Backup, recovery, and PITR Canonical URL: https://pg.edu.rich/en/docs/operations/backup-recovery Last reviewed: 2026-08-02 ## Choose the mechanism [#choose-the-mechanism] | Need | Mechanism | Boundary | | ------------------------------------------- | --------------------------------------------------- | ------------------------------------------------- | | One database, portability, object selection | `pg_dump` / `pg_restore` | Excludes cluster roles and tablespace definitions | | Logical cluster objects | `pg_dumpall --globals-only` plus per-database dumps | Slow for large systems; rebuilds indexes | | Fast whole-instance recovery | `pg_basebackup` or a mature backup tool | Stronger version/platform constraints | | Point-in-time recovery | Physical base backup plus continuous WAL archive | WAL continuity must be verified continuously | ### Choosing pgBackRest, WAL-G, or pg\_dump [#choosing-pgbackrest-wal-g-or-pg_dump] | Option | Better fit | Does not prove by itself | | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | [`pgBackRest`](https://github.com/pgbackrest/pgbackrest) | Full/differential/incremental backup, parallelism, multiple repositories, WAL, and PITR for self-hosted instances | That target RTO is met or every key and WAL file is usable | | [`WAL-G`](https://github.com/wal-g/wal-g) | Object-storage-oriented physical backup and WAL workflows | Repository retention, deletion protection, or restore correctness | | `pg_dump` / `pg_restore` | Logical migration, object selection, small restores, and cross-version export | Continuous PITR or a low-RTO whole-instance restore | | Cloud-platform backup | Lower infrastructure maintenance | Cross-account, cross-region, off-platform, or complete extension recovery | Do not copy a fixed daily/weekly schedule. Derive backup cadence from RPO, WAL volume, restore bandwidth, retention policy, and measured RTO, and keep at least one copy outside the primary database permission boundary. ## Logical backup [#logical-backup] Custom format supports parallel restore and object selection: ```bash pg_dump \ --format=custom \ --file=commerce-20260802.dump \ --dbname='postgresql://backup@db.example/commerce' pg_restore --list commerce-20260802.dump createdb commerce_restore_test pg_restore \ --dbname=commerce_restore_test \ --jobs=4 \ --exit-on-error \ commerce-20260802.dump ``` `pg_dump` provides a consistent snapshot during export but covers one database. Back up global objects separately: ```bash pg_dumpall --globals-only > globals-20260802.sql ``` Do not put globals files containing password hashes in a general artifact store. ## Physical backup and PITR [#physical-backup-and-pitr] PITR requires a usable base backup, an unbroken WAL stream from that backup, correct recovery configuration, and timeline handling. WAL alone is insufficient; a base backup alone cannot recover to an arbitrary point. An archive command returns zero only after a safe copy and never overwrites an existing file. For object storage, use a mature tool for concurrency, checksums, retention, and encryption rather than an unmonitored shell one-liner. Continuously alert on archive failures, missing WAL, repository capacity, and the latest recoverable time. Let the backup tool calculate dependency-aware retention; do not delete physical backup files solely by date. ## Restore drill [#restore-drill] Record backup id, start/end, recovery target, server version, required keys, actual RTO, latest recoverable transaction time, validation queries, and anomalies. At minimum inspect: ```sql SELECT count(*) FROM critical_table; SELECT min(created_at), max(created_at) FROM critical_table; SELECT conname, convalidated FROM pg_constraint WHERE NOT convalidated; SELECT indexrelid::regclass, indisvalid FROM pg_index WHERE NOT indisvalid; ``` Then run application-level read-only smoke tests. Matching row counts do not prove relations and privileges are correct. Replication quickly copies accidental deletes, bad updates, and logical corruption. Backups need independent retention, deletion protection, verification, and restore drills. --- # Production operations Canonical URL: https://pg.edu.rich/en/docs/operations Last reviewed: 2026-08-02 ## Define objectives first [#define-objectives-first] | Objective | Question | | ------------ | ------------------------------------------------------------ | | RPO | How much data can be lost? | | RTO | How quickly must service return? | | Capacity | What are peak connections and data/WAL/backup growth? | | Availability | Which failures auto-fail over, and which require judgment? | | Security | Who can connect, read which data, and perform which changes? | “High availability” and “we have backups” are not verifiable without targets. ## Minimal daily view [#minimal-daily-view] ```sql SELECT now(), version(); SELECT state, count(*) FROM pg_stat_activity GROUP BY state ORDER BY state; SELECT datname, age(datfrozenxid) FROM pg_database ORDER BY age(datfrozenxid) DESC; SELECT num_timed, num_requested, num_done, buffers_written, write_time, sync_time FROM pg_stat_checkpointer; SELECT buffers_clean, maxwritten_clean, buffers_alloc FROM pg_stat_bgwriter; ``` Since PostgreSQL 17, checkpoint statistics live in `pg_stat_checkpointer`; background-writer statistics remain in `pg_stat_bgwriter`. See the [PostgreSQL 18 cumulative statistics views](https://www.postgresql.org/docs/18/monitoring-stats.html#MONITORING-PG-STAT-CHECKPOINTER-VIEW) for the field definitions. Also monitor disk, WAL generation/archive, replication lag, backup state, transaction age, lock waits, query latency, autovacuum, and pool saturation. Thresholds come from this system's baseline. ## Change discipline [#change-discipline] 1. Measure lock and duration on representative data. 2. Document rollback and the point of irreversibility. 3. Set `lock_timeout` so a migration does not wait indefinitely then acquire a disruptive lock. 4. Observe locks, WAL, replication lag, and errors during execution. 5. Verify with queries and business signals. Production DDL is not done when the command succeeds. It is an observable, interruptible, verified release. --- # PostgreSQL monitoring and logs Canonical URL: https://pg.edu.rich/en/docs/operations/monitoring-logging Last reviewed: 2026-08-02 PostgreSQL observability needs at least three evidence layers: **query statistics show where resources go, metrics show when the system leaves its baseline, and logs preserve error and event context**. A single dashboard does not replace these layers. ## 1. Find workload hotspots with pg\_stat\_statements [#1-find-workload-hotspots-with-pg_stat_statements] `pg_stat_statements` is an official PostgreSQL extension. Add it to `shared_preload_libraries`, which normally requires a restart, then create it in each database that needs statistics: ```ini shared_preload_libraries = 'pg_stat_statements' compute_query_id = auto ``` ```sql CREATE EXTENSION IF NOT EXISTS pg_stat_statements; SELECT queryid, calls, total_exec_time, mean_exec_time, rows, shared_blks_hit, shared_blks_read, left(query, 160) AS query FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 20; ``` Rank total time, mean time, calls, rows, and I/O separately. The slowest individual call and the largest cumulative consumer are different problems. Statistics can reset, so record sampling windows around deployments, incidents, and configuration changes. Use the [official pg\_stat\_statements documentation](https://www.postgresql.org/docs/current/pgstatstatements.html) for field semantics. Constants are normalized, but logs, DDL, dynamic SQL, and application comments can still expose identifiers or business data. Restrict access to statistics and logs, and define collection, retention, and redaction rules. ## 2. Preserve event context with JSON logs [#2-preserve-event-context-with-json-logs] `jsonlog` makes timestamps, SQLSTATE, backend, database, user, application name, and error context reliably parseable: ```ini logging_collector = on log_destination = 'jsonlog' log_min_duration_statement = '500ms' # Example only; derive from workload baseline log_lock_waits = on deadlock_timeout = '1s' ``` Do not copy one threshold into every environment. Too low creates excessive I/O and sensitive query text; too high misses frequent medium-latency queries. Use `pg_stat_statements` for cumulative hotspots and logs for errors, lock waits, checkpoints, autovacuum, and specific slow requests. See [Error Reporting and Logging](https://www.postgresql.org/docs/current/runtime-config-logging.html). [pgBadger](https://github.com/darold/pgbadger) can process PostgreSQL native logs and `jsonlog`, producing query, connection, error, lock, checkpoint, and autovacuum reports. Stabilize format, rotation, and time zones before adding it to offline analysis. ## 3. Metrics, Prometheus, and Grafana [#3-metrics-prometheus-and-grafana] [postgres\_exporter](https://github.com/prometheus-community/postgres_exporter) fits teams already using Prometheus and Grafana. Prefer `pg_monitor` or the minimum read-only statistics privileges over superuser access: ```sql CREATE ROLE metrics LOGIN; GRANT pg_monitor TO metrics; ``` Verify collectors and privileges against the target version. Upstream still labels multi-target mode Beta, and custom `extend.query-path` queries are deprecated. Prefer built-in collectors or a separate generic SQL exporter for new custom collection rather than growing an unmaintainable query file. ### Minimum signal set [#minimum-signal-set] | Domain | Signal | Context to correlate | | --------------- | ------------------------------------------------- | ----------------------------------------------------- | | Connections | Usage, waits, pool queue | Pool mode, application replicas, reserved connections | | Queries | Latency, calls, rows, I/O | Deployments, plan changes, parameter distribution | | Transactions | Long transactions, idle in transaction, conflicts | Owner, retryability, vacuum impact | | Locks | Wait duration, blocking chain, deadlocks | DDL, batch jobs, business transactions | | WAL/replication | Generation, archive failure, lag, slot retention | RPO, network, free disk | | Maintenance | Dead tuples, freeze age, vacuum/analyze progress | Write rate and autovacuum settings | | Storage | Data/WAL/temp growth and I/O latency | Capacity forecast, checkpoints, query spills | | Recovery | Latest backup, recoverable time, measured RTO | Repository, keys, restore drills | Derive thresholds from normal and peak baselines, and make each alert lead to an actionable diagnostic path. Replication lag in bytes, time, and replay state has different meanings; one global threshold is insufficient. ## Adoption order [#adoption-order] 1. Enable and govern `pg_stat_statements` on every production instance. 2. Emit parseable logs and collect SQLSTATE, lock waits, archive failures, and autovacuum events. 3. Add postgres\_exporter and PostgreSQL-specific dashboards when Prometheus already exists. 4. Add pgBadger for log trends; evaluate [pgwatch](https://github.com/cybertec-postgresql/pgwatch) for multiple instances. 5. Evaluate [PoWA](https://github.com/powa-team/powa) for deeper workload analysis and [pg\_activity](https://github.com/dalibo/pg_activity) for interactive incident diagnosis. More tools do not automatically remove blind spots. First standardize the dimensions that connect evidence: instance, database, role, application, query ID, time window, and change event. --- # PostgreSQL production stack and HA Canonical URL: https://pg.edu.rich/en/docs/operations/production-stack Last reviewed: 2026-08-02 A useful production order is: **prove recovery → protect connection capacity → make failures observable → make changes safe → then automate failover**. High availability does not replace backup, and a replica cannot undo a deletion already replicated to it. As of **2026-08-02**, PostgreSQL 18.4 is the current minor of the newest stable major, while majors 14–18 remain supported. Production systems should run the current minor of their chosen major; being newest does not by itself justify a major upgrade. See the [PostgreSQL versioning policy](https://www.postgresql.org/support/versioning/) and [18.4 release notes](https://www.postgresql.org/docs/current/release-18-4.html). ## Minimum production baseline [#minimum-production-baseline] | Layer | First question | Common choice | | ------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------- | | Database | How are minor updates, roles, TLS, settings, and extensions controlled? | Official PostgreSQL packages or a verified image | | Connections | Can peak application concurrency exhaust backends? | Application pooling, then PgBouncer where needed | | Recovery | What are the RPO/RTO, and can recovery happen outside the platform? | pgBackRest, WAL-G, or cloud backup plus an independent copy | | Observability | Which query, wait event, metric, and log explains an incident? | `pg_stat_statements`, JSON logs, and metric collection | | Changes | How are DDL locks, backfills, rollback, and compatibility windows tested? | Expand-and-contract, migration linting, and real PostgreSQL tests | | Availability | What are the independent failure domains and post-failover data boundaries? | Managed HA, Patroni, CloudNativePG, or Pigsty | ## PgBouncer: do not assume transaction pooling [#pgbouncer-do-not-assume-transaction-pooling] [PgBouncer](https://www.pgbouncer.org/) multiplexes many client connections onto fewer PostgreSQL server connections. Repeatedly raising `max_connections` is not a capacity plan: every backend consumes memory and scheduling resources, and operations need reserved connections for migrations, monitoring, backup, administration, and replication. | Mode | Server connection returns after | Boundary | | ------------- | ------------------------------- | ----------------------------------------------------------------------------- | | `session` | Client disconnect | Highest compatibility; use when applications depend on session state | | `transaction` | Transaction end | Common for Web/API traffic, but session features must be tested | | `statement` | Every statement | Disallows multi-statement transactions; only for tightly controlled workloads | With transaction pooling, SQL-level `PREPARE`, session advisory locks, `LISTEN`, holdable cursors, and many session-state patterns are unsupported or constrained. Protocol-level prepared statements require an appropriate `max_prepared_statements` configuration and driver testing. Use the [PgBouncer feature map](https://www.pgbouncer.org/features.html) as the compatibility source. Before rollout, test authentication and TLS, prepared statements, temporary tables, migration tooling, connection reset, failover, transaction retries, and any ORM state that may be session-scoped. ## pgBackRest, WAL-G, and cloud backup [#pgbackrest-wal-g-and-cloud-backup] [pgBackRest](https://github.com/pgbackrest/pgbackrest) supports full, differential, and incremental backups, parallel transfer, multiple repositories, WAL archiving, and PITR. It is a strong fit for a complete self-hosted recovery chain. [WAL-G](https://github.com/wal-g/wal-g) is oriented toward object-storage workflows. Neither proves recoverability merely by being installed. Derive schedules from RPO, WAL volume, restore bandwidth, retention requirements, and measured RTO rather than copying a generic weekly/daily calendar. Continuously check archive gaps, deletion protection, encryption keys, cross-host or cross-account copies, and restore into a disposable instance. `pg_dump` remains valuable for logical migration, object selection, and small restores, but cannot provide continuous point-in-time recovery on its own. See [Backup, restore, and PITR](/en/docs/operations/backup-recovery). ## Choosing Patroni, CloudNativePG, or Pigsty [#choosing-patroni-cloudnativepg-or-pigsty] | Environment | Candidate | Adoption requirement | | ---------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------ | | Managed cloud database | Provider multi-zone HA | Verify region, failover, PITR, extensions, and off-platform restore limits | | Independent VMs or bare metal | [Patroni](https://github.com/patroni/patroni) | Multiple failure domains, a reliable DCS, and network/storage operations skills | | Existing Kubernetes platform | [CloudNativePG](https://cloudnative-pg.io/) | A team already capable of operating Kubernetes, storage, networking, and operator upgrades | | Multi-cluster self-hosted platform | [Pigsty](https://github.com/pgsty/pigsty) | Acceptance of its Ansible/VM model and verification of integrated component upgrades | For object-storage backup with CloudNativePG, evaluate the current [Barman Cloud Plugin](https://cloudnative-pg.io/plugin-barman-cloud/docs/intro/) rather than copying deprecated in-tree object-store configuration. Do not introduce Kubernetes solely for one PostgreSQL instance. They share host power, kernel, storage, and networking failures. Automated election improves availability only when node, storage, and quorum boundaries are genuinely independent. ## Adopt in phases [#adopt-in-phases] ### Production baseline [#production-baseline] * Current minor, role separation, TLS, and controlled extensions; * a connection budget and a tested PgBouncer deployment where required; * independently retained backups, continuous WAL/PITR, and restore drills; * query, metric, and log observability; * pre-migration lock tests, timeouts, rollback, and business validation. ### Conditional additions [#conditional-additions] * Add automatic failover only with independent failure domains and an explicit RTO; * prefer CloudNativePG only when Kubernetes operations already exist; * add Pigsty when managing multiple self-hosted clusters justifies a platform; * install pgvector, PostGIS, TimescaleDB, or other extensions only for a measured workload. ### Experimental lane [#experimental-lane] PostgreSQL 19 Beta, newer extensions, and storage engines belong in disposable compatibility environments, not in the production baseline. Keep separate CI lanes for the stable target and the next major; see [Safe migrations and zero-downtime schema changes](/en/docs/operations/safe-migrations). --- # Replication, failover, and upgrades Canonical URL: https://pg.edu.rich/en/docs/operations/replication-upgrades Last reviewed: 2026-08-02 ## Physical versus logical [#physical-versus-logical] | Dimension | Physical streaming | Logical replication | | --------------- | ------------------------------------ | ---------------------------------------------------- | | Unit | WAL / instance | Table changes | | Goal | Same-major standby, HA, read scaling | Selected tables, cross-major migration, distribution | | DDL | Physically present | Usually synchronize schema separately | | Sequences | Physically present | Handle sequence state separately | | Write conflicts | Standby is not writable | Local subscriber writes can conflict | Basic physical observations: ```sql -- primary SELECT application_name, state, sync_state, sent_lsn, write_lsn, flush_lsn, replay_lsn FROM pg_stat_replication; -- standby SELECT pg_is_in_recovery(), pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn(), now() - pg_last_xact_replay_timestamp() AS replay_delay; ``` With no new transactions, time-based replay delay can be null or misleading. Also inspect LSN distance, WAL rate, and service health. ## Replication slots [#replication-slots] Slots prevent required WAL from disappearing too early, but retain disk indefinitely when a consumer stops. Alert on slot lag and `pg_wal` capacity; confirm no consumer depends on a slot before dropping it. ```sql SELECT slot_name, slot_type, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained FROM pg_replication_slots; ``` ## Failover is not one command [#failover-is-not-one-command] A runbook confirms the primary is truly unavailable, evaluates unsent WAL, promotes the target, fences the old primary from writes, updates routing, verifies writes and background jobs, and rebuilds redundancy. Without fencing, split brain is possible. ## Upgrade paths [#upgrade-paths] * **Minor**: fixes within a major; generally replace binaries and restart, but read release notes. * **Major**: requires `pg_upgrade`, logical dump/restore, or logical replication; data directories are not forward-compatible. * You can skip intervening majors, but read every intervening release note and verify extension support. ### Major cutover checklist [#major-cutover-checklist] 1. Inventory extensions, collations, types, drivers, and topology. 2. Rehearse on a restored production copy; measure downtime, disk, and `ANALYZE` time. 3. Run application tests, critical-plan comparisons, and data validation. 4. Make source of truth explicit during freeze or dual-write. 5. Before cutover, confirm catch-up, clear long transactions, and retain the rollback window. 6. After cutover, refresh statistics and inspect invalid objects, errors, performance, and backups. For the major currently in testing, use the [PostgreSQL 19 release and 18-to-19 upgrade guide](/en/docs/postgresql-19) to check Beta status, incompatibilities, and the `pg_upgrade --check` workflow. Each PostgreSQL major is normally supported for five years. New systems should run the newest minor of a supported major. As of August 2026, 18, 17, 16, 15, and 14 are supported; 14 reaches end of support in November 2026. See [Version policy](/en/docs/reference/version-policy). --- # Safe PostgreSQL schema migrations Canonical URL: https://pg.edu.rich/en/docs/operations/safe-migrations Last reviewed: 2026-08-02 Zero downtime is not an intrinsic property of one DDL statement. It depends on **whether old and new application versions can operate together during the migration window**. Safe migration needs compatibility phases, a lock budget, representative-scale tests, observable execution, and explicit rollback boundaries. ## Default to expand-and-contract [#default-to-expand-and-contract] For a renamed or replaced field on a high-traffic table: 1. **Expand**: add the new column or table without removing the old structure; prefer short metadata operations. 2. **Dual compatible**: make the application read both structures and dual-write when required; writes must be idempotent. 3. **Backfill**: use small primary-key or time ranges and bound transaction duration, WAL, and replica lag. 4. **Switch**: change reads first, then stop old writes; verify with business signals and consistency queries. 5. **Contract**: remove the old structure only after a full rollback-compatible release window. Putting “add, backfill, set `NOT NULL`, and drop old” in one long transaction often amplifies lock, WAL, rollback, and replication-lag risk. ## Bound lock waits [#bound-lock-waits] ```sql BEGIN; SET LOCAL lock_timeout = '2s'; SET LOCAL statement_timeout = '15min'; ALTER TABLE app.orders ADD COLUMN IF NOT EXISTS fulfillment_state text; COMMIT; ``` These timeouts are examples, not universal defaults. `lock_timeout` prevents a migration from waiting indefinitely and acquiring a strong lock at an uncontrolled moment; `statement_timeout` bounds execution. On failure, exit and investigate the blocker instead of retrying forever. Constraint scanning can be separated from the short-lock phase: ```sql ALTER TABLE app.orders ADD CONSTRAINT orders_total_nonnegative CHECK (total_cents >= 0) NOT VALID; ALTER TABLE app.orders VALIDATE CONSTRAINT orders_total_nonnegative; ``` Check the exact DDL lock level on the target PostgreSQL version and representative data. `CREATE INDEX CONCURRENTLY` still consumes I/O, WAL, and time, and a failure can leave an invalid index that must be detected. ## Recommended CI pipeline [#recommended-ci-pipeline] ```text Schema / reviewed SQL ↓ Migration generation ↓ Squawk static checks ↓ Disposable PostgreSQL 18.4 ↓ Apply every migration from empty and upgraded states ↓ pgTAP + application integration + RLS negative tests ↓ PostgreSQL 19 Beta compatibility lane ↓ Representative-data rehearsal → staging → production ``` * [Squawk](https://github.com/sbdchd/squawk) detects common hazards such as non-concurrent indexes, constraints added without `NOT VALID`, and selected lock risks; it is not proof of zero downtime. * [Testcontainers for Node.js](https://github.com/testcontainers/testcontainers-node) starts real PostgreSQL in CI for transactions, locks, RLS, JSONB, extensions, and driver behavior. * [pgTAP](https://github.com/theory/pgtap) tests functions, triggers, constraints, and policies inside PostgreSQL. With Drizzle ORM, Drizzle Kit can generate ordinary schema changes before Squawk and human review. Use reviewed native SQL for complex indexes, policies, functions, extensions, and PostgreSQL 19 syntax. An ORM's inability to express a feature does not make the database feature inappropriate. ## Test the upgrade path, not only an empty database [#test-the-upgrade-path-not-only-an-empty-database] CI needs at least two starting states: | Starting point | Problems exposed | | --------------------------------------------------------------- | -------------------------------------------------------- | | Empty database running every migration | Ordering, dependencies, syntax, and bootstrap | | Production schema or masked data running incremental migrations | Locks, backfills, old data, constraints, and performance | Split version tests into two lanes: * **Production gate**: the current production major/minor, such as PostgreSQL 18.4; failures block release. * **Forward compatibility**: PostgreSQL 19 Beta 2; failures may initially be allowed but must be classified, tracked, and cleared before GA adoption. Beta testing does not replace the stable-version gate. Follow version status on the [PostgreSQL 19 topic page](/en/docs/postgresql-19). ## RLS and security objects need negative tests [#rls-and-security-objects-need-negative-tests] A successful migration does not prove correct authorization. For every tenant and role, verify that allowed `SELECT/INSERT/UPDATE/DELETE` operations succeed and forbidden cross-tenant reads and writes fail. The runtime role should not own tables; use `FORCE ROW LEVEL SECURITY` where required. See the [Security baseline](/en/docs/operations/security). Dropped columns, irreversible backfills, narrowed types, and external side effects may not reverse safely. Every release needs a last rollback point, an answer for whether the old app can read the new schema, and criteria for a forward fix. ## When heavier tooling is justified [#when-heavier-tooling-is-justified] | Tool | Useful when | Verify before adoption | | ------------------------------------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------- | | [pgroll](https://github.com/xataio/pgroll) | High-frequency changes with explicit compatibility windows | Supported DDL, proxy/connection path, rollback semantics | | [Bytebase](https://github.com/bytebase/bytebase) | Multi-team approval, SQL review, environment, and audit governance | Permission boundaries, deployment model, existing CI integration | | [Database Lab Engine](https://github.com/postgres-ai/database-lab-engine) | Fast clones and migration rehearsal for large databases | Storage, masking, clone lifecycle, and cost | Small teams should first make expand-and-contract, real PostgreSQL tests, lock observation, and recovery drills routine before adding a control plane. --- # Security baseline Canonical URL: https://pg.edu.rich/en/docs/operations/security Last reviewed: 2026-08-02 ## Separate roles [#separate-roles] ```sql CREATE ROLE app_owner NOLOGIN; CREATE ROLE app_runtime LOGIN; CREATE ROLE app_migrator LOGIN NOINHERIT; CREATE SCHEMA app AUTHORIZATION app_owner; GRANT app_owner TO app_migrator; GRANT CONNECT ON DATABASE commerce TO app_runtime, app_migrator; GRANT USAGE ON SCHEMA app TO app_runtime; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app TO app_runtime; ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_runtime; ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA app GRANT USAGE, SELECT ON SEQUENCES TO app_runtime; ``` Runtime does not own objects, the migrator uses `SET ROLE app_owner` only during migrations, and the owner cannot log in. `ALTER DEFAULT PRIVILEGES` affects future objects created by the specified creator; it does not repair existing privileges. ## Authentication and network [#authentication-and-network] * Listen only on required interfaces and restrict sources with firewall/security groups. * Require TLS remotely and verify the server certificate; consider client certificates for sensitive systems. * Use SCRAM for new password authentication and retire MD5 configuration. * Order `pg_hba.conf` from narrow rules to broad ones by network, database, and role; reload and test both allow and deny paths. * Separate administrative and application entry points; do not expose the database port publicly. ## Protect search\_path [#protect-search_path] Do not resolve names through untrusted writable schemas. Revoke default create privilege on `public` and pin paths for sensitive functions: ```sql REVOKE CREATE ON SCHEMA public FROM PUBLIC; CREATE FUNCTION app.current_tenant() RETURNS bigint LANGUAGE sql STABLE SECURITY DEFINER SET search_path = pg_catalog, app AS $$ SELECT current_setting('app.tenant_id')::bigint $$; REVOKE ALL ON FUNCTION app.current_tenant() FROM PUBLIC; GRANT EXECUTE ON FUNCTION app.current_tenant() TO app_runtime; ``` `SECURITY DEFINER` runs with owner privilege. Audit every input, qualified object name, search path, and execute grant. ## Row-level security [#row-level-security] ```sql ALTER TABLE app.orders ENABLE ROW LEVEL SECURITY; ALTER TABLE app.orders FORCE ROW LEVEL SECURITY; CREATE POLICY tenant_orders ON app.orders USING (tenant_id = current_setting('app.tenant_id')::bigint) WITH CHECK (tenant_id = current_setting('app.tenant_id')::bigint); ``` With RLS enabled, no applicable policy means default deny. Superusers, `BYPASSRLS`, and normally table owners can bypass; `FORCE ROW LEVEL SECURITY` subjects owners during ordinary access. Normal object privileges still apply. An administrator's result cannot prove RLS. Test the allowed tenant, another tenant, missing context, inserts, and updates. Confirm the pool sets and clears tenant context on every checkout/return. ## Secrets and logs [#secrets-and-logs] Rotate and shorten credentials and distribute them via a secret manager. Avoid bound values and sensitive DDL in database logs; restrict audit-log access and retention. `pg_stat_activity` can expose query text, so monitoring-view privilege also matters. --- # Troubleshoot PostgreSQL connection errors Canonical URL: https://pg.edu.rich/en/docs/reference/connection-errors Last reviewed: 2026-08-02 When failure happens before SQL execution, the client may not receive SQLSTATE. Preserve the complete error, timestamp, client version, and target host/port—but never the password. ## Fixed diagnostic order [#fixed-diagnostic-order] ```text DNS resolution → TCP route/firewall/listening port → TLS negotiation and certificate identity → pg_hba.conf match → user authentication → database and CONNECT privilege → instance/pool connection capacity → session initialization settings ``` Resetting passwords or widening privileges before proving the previous layer usually hides the real cause. ## Frequent errors [#frequent-errors] | Error | Meaning | Verify | | -------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------ | | `could not translate host name` | DNS/hostname cannot resolve | `getent hosts`, `nslookup`, spelling, and private DNS | | `connection refused` | Nothing accepts the target address/port | Service state, `listen_addresses`, port, and container mapping | | `connection timed out` | Network path or firewall drops traffic | Test TCP from the application environment, not a laptop substitute | | `no pg_hba.conf entry` | No rule matches source/database/user/TLS | Inspect server log and rule order; reload after editing | | `password authentication failed` | Credential or authentication method mismatch, commonly SQLSTATE `28P01` | Confirm target instance/user and rotate securely | | `database ... does not exist` | Database absent on this instance, SQLSTATE `3D000` | Connect to `postgres` and inspect `pg_database` | | `too many connections` | Instance/role/database limit exhausted, SQLSTATE `53300` | `pg_stat_activity`, pool size, and reserved administration access | | `certificate verify failed` | CA, hostname, validity, or chain mismatch | `sslmode`, URI host, CA file, and provider rotation notice | ## Client verification [#client-verification] ```bash psql --version psql -X "postgresql://app_reader@db.example.com:5432/commerce?sslmode=verify-full" ``` Immediately after success: ```sql \conninfo SELECT current_database(), current_user, inet_server_addr(), inet_server_port(), current_setting('server_version'); ``` ## Minimal server-side checks [#minimal-server-side-checks] ```sql SELECT datname, datallowconn, datconnlimit FROM pg_database ORDER BY datname; SELECT usename, application_name, client_addr, state, count(*) FROM pg_stat_activity GROUP BY usename, application_name, client_addr, state ORDER BY count(*) DESC; ``` Use OS access only when needed to inspect listening sockets, firewalls, and PostgreSQL logs. For managed databases, use provider connection diagnostics, network flow logs, and audit logs. Changing `pg_hba.conf` to `trust` removes the authentication boundary and does not explain the original failure. Rotate credentials through a controlled channel and identify the matching HBA rule and server log entry. For a secure successful connection, see [`psql` and SSL](/en/docs/setup/psql-connection). For SQL execution failures, use the [SQLSTATE fieldbook](/en/docs/reference/errors). --- # Editorial and verification policy Canonical URL: https://pg.edu.rich/en/docs/reference/editorial-policy Last reviewed: 2026-08-02 ## Accountability [#accountability] PostgreSQL Field Guide is an independent community knowledge base. It is not affiliated with the PostgreSQL Global Development Group or the cloud vendors it covers. The site provides learning paths, engineering explanations, and verifiable examples; the official documentation for the target PostgreSQL version remains normative. ## Source priority [#source-priority] 1. Official manuals, release notes, and versioning pages for supported PostgreSQL versions. 2. Upstream repositories and release notes for extensions such as pgvector. 3. Vendor documentation bound to a specific product, region, and engine version. 4. Reproducible local tests and public technical standards. Community articles can help discover questions, but never stand alone for version, API, security, or recovery claims. ## Publication checks [#publication-checks] * Verify SQL names, catalog views, and settings against the target-version manual instead of recalling interfaces. * Run safely executable examples against an ephemeral PostgreSQL 18 instance where practical. * State risks and prerequisites for writes, disruptive locks, recovery, privilege, and replication. * Publish matching Chinese and English paths; neither language may be an empty placeholder or unreviewed machine translation. * Date cloud-service claims and require readers to re-check region, SKU, and extension versions. * Pass type checking, lint, production build, internal-link validation, and critical HTTP/SEO checks. ## AI assistance disclosure [#ai-assistance-disclosure] AI may assist research organization, translation drafts, example review, and consistency checks. It is not a factual source. Database-behavior claims must resolve to official material or reproducible tests; business semantics, risk acceptance, and production changes remain human decisions. ## Dates and corrections [#dates-and-corrections] The “Last updated” marker represents the latest content-review date. Corrections should update both languages, cross-links, and machine-readable Markdown together, with a traceable note in the project's content audit record. Current site-wide review baseline: **2026-08-02**. --- # SQLSTATE error fieldbook Canonical URL: https://pg.edu.rich/en/docs/reference/errors Last reviewed: 2026-08-02 Applications branch on **SQLSTATE**, not error text that can vary by version and locale. ## Frequent states [#frequent-states] | SQLSTATE | Name | Common meaning | Safe action | | -------- | ----------------------------- | ---------------------------------------- | ------------------------------------------------------- | | `23505` | unique\_violation | Unique key conflict | Return conflict or use explicit `ON CONFLICT` semantics | | `23503` | foreign\_key\_violation | Target absent or still referenced | Fix operation order; do not disable the constraint | | `23502` | not\_null\_violation | Required column absent | Fix input or migration order | | `23514` | check\_violation | `CHECK` rejected the row | Explain boundary and correct the value | | `22P02` | invalid\_text\_representation | Type conversion failed | Validate at the boundary and bind the right type | | `40001` | serialization\_failure | Isolation guarantee cannot be maintained | Roll back and retry the entire transaction | | `40P01` | deadlock\_detected | Wait cycle | Roll back whole transaction; normalize lock order | | `55P03` | lock\_not\_available | `NOWAIT` or lock timeout | Retry later or return conflict | | `57014` | query\_canceled | Statement timeout or cancellation | Distinguish cancel from timeout; optimize or narrow | | `25P02` | in\_failed\_sql\_transaction | Earlier statement failed | `ROLLBACK`; do not continue business SQL | | `42501` | insufficient\_privilege | Action/object not granted | Fix grant/owner; do not jump to superuser | | `42P01` | undefined\_table | Missing table or wrong search path | Check database/schema/migration version | | `42703` | undefined\_column | Column absent | Check schema contract and deploy version | | `53300` | too\_many\_connections | Connection slots exhausted | Inspect pools, leaks, and reserved admin access | | `57P03` | cannot\_connect\_now | Starting, recovering, or shutting down | Bounded backoff and instance inspection | | `08006` | connection\_failure | Connection failed | Determine unknown commit state before safe retry | ## After a transaction error [#after-a-transaction-error] An error inside a transaction normally leaves it aborted: ```text ERROR: current transaction is aborted... SQLSTATE: 25P02 ``` Issue `ROLLBACK`, or roll back to a savepoint created before the failure. More statements do not repair it automatically. ## Retry classes [#retry-classes] * **Retry the whole transaction**: `40001`, `40P01`; bounded attempts, exponential backoff, and jitter. * **Possibly transient**: `55P03`, `57P03`, selected `08***`; verify idempotency and unknown commit state. * **Input/model errors—do not blind retry**: `22***`, `23***`, `42***`, `42501`. * **Resource conditions**: `53300`, disk full, memory pressure; retries amplify the incident. Shed load and repair capacity. ## Diagnostic context [#diagnostic-context] Record SQLSTATE, constraint/table/column fields, database and schema, application and migration versions, transaction/request id, parameter types with sensitive values redacted, and known commit state. Drivers usually expose structured fields; use them directly. ## AI tool response [#ai-tool-response] ```json { "ok": false, "sqlstate": "23505", "category": "constraint", "retryable": false, "constraint": "customers_email_unique", "message_safe": "A customer with this email already exists" } ``` Do not return raw database errors to end users without filtering. They may reveal object names, paths, or data fragments. --- # PostgreSQL extension selection guide Canonical URL: https://pg.edu.rich/en/docs/reference/extensions-ecosystem Last reviewed: 2026-08-02 PostgreSQL extensions can place types, indexes, planner hooks, background workers, and storage behavior inside the database process. They also enter the critical path for backup, replication, recovery, and major upgrades. The selection rule is simple: **do not install an extension without a defined workload and exit path**. ## Six gates before installation [#six-gates-before-installation] 1. The target PostgreSQL major, operating system, and CPU architecture have explicit support and packages. 2. The license fits self-hosting, SaaS, redistribution, and commercial-feature boundaries. 3. Backup, PITR, standbys, logical replication, and recovery environments can load the same version. 4. `pg_upgrade`, extension update, and any required index rebuild have a rehearsed path. 5. The managed-cloud region, SKU, and allowlist provide the required version, not merely an extension with the same name. 6. An export or migration path exists without the extension, limiting accidental platform lock-in. Record `SELECT extname, extversion FROM pg_extension`, and place extension versions beside the database version in deployment manifests and AI context. First check native B-tree/GIN/GiST/SP-GiST/BRIN, full-text search, partitions, FDWs, and materialized views in [PostgreSQL index and storage access methods](/en/docs/reference/index-access-methods). Add an extension only when native behavior fails a measured workload requirement. ## Choose by workload [#choose-by-workload] | Workload | Common candidate | Adoption boundary | | ---------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | SQL statistics | [`pg_stat_statements`](https://www.postgresql.org/docs/current/pgstatstatements.html) | Official contrib and an observability baseline; govern query-text access | | Vector search / RAG | [pgvector](https://github.com/pgvector/pgvector) | Measure recall, latency, memory, and index build with real filters | | Geospatial | [PostGIS](https://postgis.net/) | Standard GIS choice; verify extension and data-format upgrades | | Time series | [TimescaleDB](https://github.com/timescale/timescaledb) | Evaluate for hypertables, compression, or continuous aggregates; check licensing feature by feature | | Distributed multi-tenancy | [Citus](https://github.com/citusdata/citus) | Add only after measuring a single-node bottleneck and stabilizing a shard key | | BM25 / search | [ParadeDB / pg\_search](https://github.com/paradedb/paradedb) | Verify license, index recovery, replication, and cloud support | | In-PostgreSQL BM25 | [pg\_textsearch](https://github.com/timescale/pg_textsearch) | Upstream currently calls it production ready; independently validate target version and corpus | | Embedded analytics / Parquet | [pg\_duckdb](https://github.com/duckdb/pg_duckdb) | Fit for analytics paths; test transaction boundaries, resource isolation, and object-store credentials | | Iceberg columnstore mirror | [pg\_mooncake](https://github.com/Mooncake-Labs/pg_mooncake) | Maintains a columnstore mirror from logical changes; validate consistency, object storage, pg\_duckdb dependency, and recovery | | Graph queries | [Apache AGE](https://github.com/apache/age) | Adopt only when a graph model and Cypher produce measured value | “Production ready” is an upstream project status, not a certification for your workload, SLA, or cloud platform. ## Maintenance and data governance [#maintenance-and-data-governance] | Tool | Purpose | Do not mistake it for | | ------------------------------------------------------------------------ | ----------------------------------------------------------------- | ----------------------------------------------------------- | | [HypoPG](https://github.com/HypoPG/hypopg) | Evaluate planner choices with hypothetical indexes | Proof of build cost or production benefit | | [pg\_repack](https://github.com/reorg/pg_repack) | Reorganize tables and indexes with shorter exclusive-lock windows | A replacement for routine autovacuum | | [pg\_partman](https://github.com/pgpartman/pg_partman) | Manage native time/serial partition lifecycles | An automatic fix for a poor partition key | | [pg\_cron](https://github.com/citusdata/pg_cron) | Schedule simple SQL inside PostgreSQL | A general business queue or workflow engine | | [Greenmask](https://github.com/GreenmaskIO/greenmask) | Produce masked and subsetted test data | Permission to copy sensitive production data without review | | [PostgreSQL Anonymizer](https://gitlab.com/dalibo/postgresql_anonymizer) | Declarative static and dynamic masking | Automatic compliance with every requirement | For severe bloat, first find long transactions, autovacuum, write patterns, and fillfactor causes before using pg\_repack. Partitioning helps only where lifecycle and queries can use the partition key. ## PostgreSQL 19 REPACK is not pg\_repack [#postgresql-19-repack-is-not-pg_repack] The core [`REPACK`](https://www.postgresql.org/docs/19/sql-repack.html) in PostgreSQL 19 Beta is a new SQL command. `REPACK (CONCURRENTLY)` uses logical decoding and has constraints around primary keys or replica identity, unlogged/partitioned/system tables, replication slots, and disk space. Third-party **pg\_repack** is an independent extension and command-line tool with its own compatibility matrix, packages, and operational boundaries. Similar names do not make pg\_repack experience, monitoring, or risks directly transferable to core PostgreSQL 19 `REPACK`. As of 2026-08-02, PostgreSQL 19 remains Beta 2. Validate core REPACK semantics and constraints against final GA documentation and a restored copy of your own data. ## AI, backup, and upgrade checklist [#ai-backup-and-upgrade-checklist] Provide AI agents with `server_version_num`, `extname/extversion`, allowed operators and index methods, cloud limitations, and forbidden syntax. “This is PostgreSQL” is insufficient context. Before every extension upgrade: 1. Read target release notes, SQL update scripts, and known rebuild requirements. 2. Restore a real backup into an isolated environment. 3. Upgrade PostgreSQL and the extension, then run integrity, performance, and RLS tests. 4. Rebuild required indexes and compare plans, recall, or business results. 5. Create a new backup and restore it once to prove the new-version chain. Supabase, Neon, YugabyteDB, CockroachDB, Cloudberry, Gel, and FerretDB do not belong in an extension ranking. They are platforms, forks, independent databases, or protocol translation layers; classify them with [PostgreSQL lineage and compatible databases](/en/docs/reference/postgresql-compatible-databases). --- # PostgreSQL index access methods Canonical URL: https://pg.edu.rich/en/docs/reference/index-access-methods Last reviewed: 2026-08-02 PostgreSQL does not use the everyday MySQL model of selecting InnoDB or MyISAM for ordinary tables. Almost every table uses the core **heap table access method**. Separate index access methods and operator classes determine which queries an index supports. ## A table access method is not a routine tuning switch [#a-table-access-method-is-not-a-routine-tuning-switch] The PostgreSQL [Table Access Method API](https://www.postgresql.org/docs/current/tableam.html) lets extensions or custom builds implement table storage, but ordinary applications still default to `heap`: ```sql CREATE TABLE events ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, occurred_at timestamptz NOT NULL, payload jsonb NOT NULL ) USING heap; ``` `USING heap` is normally omitted. A new table access method enters the critical path for WAL, MVCC, VACUUM, backup, replication, extensions, and major upgrades. It is not a query hint that can be switched casually. Inspect access methods exposed by an instance: ```sql SELECT amname, CASE amtype WHEN 't' THEN 'table' WHEN 'i' THEN 'index' ELSE amtype::text END AS access_method_type FROM pg_am ORDER BY amtype, amname; ``` ## Core index access methods [#core-index-access-methods] PostgreSQL 18 core provides B-tree, Hash, GiST, SP-GiST, GIN, and BRIN. `bloom` ships as a module but requires `CREATE EXTENSION bloom`. Use the official [Index Types](https://www.postgresql.org/docs/current/indexes-types.html) as the behavior boundary. | Type | Prefer for | Critical boundary | | --------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | B-tree | Equality, ranges, ordering, uniqueness, anchored patterns | Default choice; column order and operator class determine usable queries | | Hash | Single-column equality | Supports only `=`; B-tree is usually more versatile, so require measured benefit | | GIN | JSONB, arrays, full text, and multi-valued content | Higher update/build cost; behavior depends on the operator class | | GiST | Ranges, geometry, PostGIS, and nearest-neighbor search | An extensible framework, not one algorithm; operators/classes must match | | SP-GiST | Tries, quadtrees, k-d trees, and partitioned search spaces | Fits naturally partitionable data; not a general GiST replacement | | BRIN | Very large append-heavy tables correlated with physical order | Stores block-range summaries; weak correlation reads many heap blocks | | Bloom extension | Equality across arbitrary combinations of many columns | Lossy and rechecked; no range, unique, or `NULL` search; bundled operator classes cover only `int4` and `text` | GIN, GiST, SP-GiST, and BRIN are frameworks. The operator class determines supported operators, ordering, and data types. “Uses GIN” is not enough information to reproduce an index design. ## Common workload map [#common-workload-map] ```text Equality / range / order / unique → B-tree JSONB contains / array member → GIN PostgreSQL full-text search → GIN in most cases Range / GIS / nearest neighbor → GiST or a matching SP-GiST class Huge, time-correlated append table → BRIN Vector approximate-nearest-neighbor → pgvector HNSW / IVFFlat ``` HNSW and IVFFlat come from [pgvector](https://github.com/pgvector/pgvector); they are not core PostgreSQL index methods. Test recall, filtering, memory, build time, WAL, replica lag, and extension upgrades independently. Built-in full-text search includes parsers, dictionaries, ranking, highlighting, and GIN/GiST indexing. Built-in configurations do not solve tokenization for every language. Chinese, for example, normally needs an additional tokenizer/extension or application preprocessing; creating a GIN index alone does not prove search quality. ## Match the query before creating an index [#match-the-query-before-creating-an-index] ```sql -- Ordinary filter and order CREATE INDEX CONCURRENTLY orders_customer_time_idx ON orders (customer_id, placed_at DESC); -- JSONB containment: payload @> '{"status":"paid"}' CREATE INDEX CONCURRENTLY events_payload_gin_idx ON events USING gin (payload jsonb_path_ops); -- Large table whose timestamps correlate with physical append order CREATE INDEX CONCURRENTLY events_time_brin_idx ON events USING brin (occurred_at); ``` `jsonb_path_ops` is focused on containment and jsonpath operators such as `@>`, `@?`, and `@@`; it does not support every operator available from the default `jsonb_ops`. Derive index DDL from real query shapes. Record plans and size after creation: ```sql SELECT indexrelname, idx_scan, pg_size_pretty(pg_relation_size(indexrelid)) AS index_size FROM pg_stat_user_indexes WHERE relname = 'events' ORDER BY pg_relation_size(indexrelid) DESC; ``` Then use `EXPLAIN (ANALYZE, BUFFERS)` to compare actual rows, heap blocks, rechecks, sorting, and write cost. See [Indexes and EXPLAIN](/en/docs/core/indexes-explain) for the complete workflow. ## Prefer native capability first [#prefer-native-capability-first] | Need | Validate in PostgreSQL first | Evaluate only when insufficient | | --------------------- | ------------------------------------------------------ | ---------------------------------------- | | Fuzzy search | FTS, `pg_trgm` contrib, expression/GIN/GiST indexes | External search or a BM25 extension | | Work claiming | Transactions, `FOR UPDATE SKIP LOCKED`, advisory locks | Dedicated queue and workflow systems | | Time lifecycle | Native partitions, BRIN, scheduled cleanup | pg\_partman or TimescaleDB | | Cross-database access | `postgres_fdw`, logical replication | CDC platform or separate sync system | | Analytics | Materialized views, partitioning, parallel query | pg\_duckdb, pg\_mooncake, or a warehouse | | Vector search | No core vector type or ANN index | pgvector or a dedicated vector system | Native-first does not reject extensions. It avoids unnecessary binary, license, backup, and upgrade dependencies. See [PostgreSQL extension selection](/en/docs/reference/extensions-ecosystem) for candidates. --- # PostgreSQL field reference Canonical URL: https://pg.edu.rich/en/docs/reference Last reviewed: 2026-08-02 ## psql [#psql] ```bash psql 'postgresql://user@host:5432/database?sslmode=verify-full' psql -X --set ON_ERROR_STOP=on --file migration.sql "$DATABASE_URL" ``` | Command | Purpose | | ---------------- | ----------------------------------------------- | | `\conninfo` | Current connection | | `\l` | Databases | | `\dn` | Schemas | | `\dt app.*` | Tables | | `\d+ app.orders` | Object definition and storage detail | | `\du` | Roles | | `\dx` | Extensions | | `\timing on` | Client-observed duration | | `\x auto` | Expanded output for wide results | | `\gdesc` | Describe result columns without displaying rows | | `\q` | Quit | Scripts use `-X` to ignore a user's `.psqlrc` and `ON_ERROR_STOP` to exit at the first error. ## Current context [#current-context] ```sql SELECT version(), current_database(), current_user, session_user, current_schema(), current_setting('TimeZone') AS timezone, inet_server_addr(), inet_server_port(); ``` ## Object size [#object-size] ```sql SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) AS total, pg_size_pretty(pg_relation_size(relid)) AS heap, pg_size_pretty(pg_indexes_size(relid)) AS indexes FROM pg_catalog.pg_statio_user_tables ORDER BY pg_total_relation_size(relid) DESC LIMIT 20; ``` ## Active sessions and old transactions [#active-sessions-and-old-transactions] ```sql SELECT pid, usename, application_name, state, now() - xact_start AS xact_age, wait_event_type, wait_event, left(query, 160) AS query FROM pg_stat_activity WHERE pid <> pg_backend_pid() ORDER BY xact_start NULLS LAST; ``` ## Blocking graph [#blocking-graph] ```sql SELECT blocked.pid AS blocked_pid, blocker.pid AS blocker_pid, now() - blocked.query_start AS blocked_for, left(blocked.query, 120) AS blocked_query, left(blocker.query, 120) AS blocker_query FROM pg_stat_activity AS blocked CROSS JOIN LATERAL unnest(pg_blocking_pids(blocked.pid)) AS b(pid) JOIN pg_stat_activity AS blocker ON blocker.pid = b.pid; ``` Do not immediately call `pg_terminate_backend` on a blocker. Identify the workload, transaction, retry behavior, and termination impact first. ## Safe session settings [#safe-session-settings] ```sql BEGIN; SET LOCAL statement_timeout = '10s'; SET LOCAL lock_timeout = '2s'; SET LOCAL search_path = app, pg_catalog; -- work COMMIT; ``` ## Diagnostic order [#diagnostic-order] Confirm target and role → record SQLSTATE → inspect transaction state → inspect waits/blockers → capture plan and statistics → reproduce safely → run a verification query after the fix. Before a session exists, use [PostgreSQL connection troubleshooting](/en/docs/reference/connection-errors). For SQL failures after connection, use the [error and SQLSTATE fieldbook](/en/docs/reference/errors). For upgrade boundaries around extensions, maintenance tools, and open-source components, use the [PostgreSQL extensions and ecosystem guide](/en/docs/reference/extensions-ecosystem). See [PostgreSQL index and storage access methods](/en/docs/reference/index-access-methods) for storage concepts, and [PostgreSQL lineage and compatible databases](/en/docs/reference/postgresql-compatible-databases) for forks and protocol compatibility. --- # PostgreSQL compatible database guide Canonical URL: https://pg.edu.rich/en/docs/reference/postgresql-compatible-databases Last reviewed: 2026-08-02 “Built on PostgreSQL,” “uses the PostgreSQL protocol,” and “can replace PostgreSQL” are three different claims. Compatibility has at least five layers: ```text A driver connects → pgwire messages work → SQL, types, and functions match → catalogs, extensions, and transactions match → backup, replication, upgrade, and failure semantics match ``` Each deeper layer needs migration and failure testing. A PostgreSQL-compatible label usually describes only part of this stack. ## Developer platforms centered on PostgreSQL [#developer-platforms-centered-on-postgresql] | Platform | Where PostgreSQL sits | Platform additions | Do not assume | | ------------------------------------------------------ | -------------------------------------------- | --------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | [Supabase](https://github.com/supabase/supabase) | Each project runs PostgreSQL | PostgREST, Auth, Realtime, Storage, Functions, Dashboard, and pooling | Cloud and self-hosted operations are identical, or browser APIs are secure automatically | | [Neon](https://github.com/neondatabase/neon) | Compute nodes run the PostgreSQL query layer | Separated compute/storage, page servers, branches, and scale-to-zero | Data directory, WAL, unlogged tables, and recovery behave like ordinary PostgreSQL | | [Nhost](https://github.com/nhost/nhost) | PostgreSQL is the database | Hasura GraphQL, Auth, Storage, and Functions | GraphQL permissions are the complete database security boundary | | [Prisma Postgres](https://www.prisma.io/docs/postgres) | Managed PostgreSQL | PgBouncer, HTTP/edge driver, query cache, temporary databases, and Prisma tooling | Operation billing, pooling, and extensions match every self-hosted installation | These platforms preserve ordinary SQL, migration, and `pg_dump` thinking, but their connection proxies, sleep behavior, backups, extension allowlists, API permissions, and billing belong in the architecture. ## Forks, reused query layers, and new storage [#forks-reused-query-layers-and-new-storage] | Project | Implementation path | Primary target | Migration risk center | | --------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | [YugabyteDB](https://github.com/yugabyte/yugabyte-db) | YSQL reuses the PostgreSQL query layer over distributed DocDB | Distributed transactions, horizontal scale, and multi-region | Extensions, locks/isolation, catalogs, DDL, and distributed cost model | | [PolarDB for PostgreSQL](https://github.com/polardb/PolarDB-for-PostgreSQL) | Compute/storage-separated PostgreSQL-lineage fork | Shared storage, one writer/many readers, cloud architecture | Open-source version cadence, specialized storage/HA, and differences from the hosted product | | [Apache Cloudberry](https://github.com/apache/cloudberry) | Greenplum/PostgreSQL-lineage MPP database | Warehousing and massively parallel analytics | OLTP transactions, distribution keys, SQL/extensions, and operational tooling | | [IvorySQL](https://github.com/IvorySQL/IvorySQL) | Oracle-compatible fork tracking PostgreSQL | PL/iSQL, Oracle syntax, packages, and migration | Compatibility mode, Oracle semantics, extension packaging, and upstream synchronization | | [openGauss](https://github.com/opengauss-mirror/openGauss-server) | Independent database kernel with PostgreSQL lineage | Enterprise deployment, parallelism, and its own ecosystem | Long independent evolution means current PostgreSQL compatibility is not a default | | [OrioleDB](https://github.com/orioledb/orioledb) | New PostgreSQL storage engine, generally on a supported build | Undo-based MVCC, copy-on-write/checkpointing, and reduced bloat for selected workloads | Binary/build, WAL/backup, extensions, major upgrade, and failure recovery | Lineage is not a drop-in guarantee. Distributed storage in particular changes transaction retries, hot keys, sequences, foreign keys, locks, and consistency/latency tradeoffs. ## PostgreSQL clients work, but the server is not PostgreSQL [#postgresql-clients-work-but-the-server-is-not-postgresql] | Project | Role of pgwire/PostgreSQL | Actual product | | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | [CockroachDB](https://www.cockroachlabs.com/docs/stable/postgresql-compatibility) | Implements pgwire and much PostgreSQL syntax | Independent distributed SQL database with different extensions, catalogs, and transaction behavior | | [Materialize](https://github.com/MaterializeInc/materialize) | PostgreSQL-compatible drivers query views | Streaming incremental-compute and live-data layer, not general-purpose OLTP PostgreSQL | | [Gel](https://github.com/geldata/gel) | Uses PostgreSQL technology underneath and offers SQL/ecosystem integration | Graph-relational database whose primary model and language are Gel/EdgeQL | Compatible databases may report a PostgreSQL-like `server_version` or expose similar catalogs. A version string helps a driver choose a protocol path; it does not prove the same PostgreSQL kernel is running. ## FerretDB is compatibility in the opposite direction [#ferretdb-is-compatibility-in-the-opposite-direction] [FerretDB 2.x](https://github.com/FerretDB/FerretDB) accepts MongoDB 5.0+ wire-protocol requests, translates them to SQL, and uses PostgreSQL with the DocumentDB extension as its database engine: ```text MongoDB driver → FerretDB proxy → PostgreSQL + DocumentDB extension ``` It is not a PostgreSQL client connecting to a MongoDB-compatible server. It is a MongoDB client using a PostgreSQL-backed document database. Test the MongoDB command/BSON matrix, DocumentDB extension, indexes, transactions, backup, and exact version combination. ## Migration compatibility matrix [#migration-compatibility-matrix] | Layer | Required tests | Insufficient evidence | | ------------ | --------------------------------------------------------------------- | ------------------------------------------------ | | Connection | TLS, SCRAM, startup parameters, prepared statements, pooling | `psql` runs `SELECT 1` | | Schema | Types, identity/sequences, generated columns, constraints, partitions | ORM migration succeeds only on an empty database | | SQL | Functions/operators, JSONB, CTE/windows, collations, full text | Basic CRUD works | | Transactions | Isolation, retries, row locks, deadlocks, advisory locks | A product page says “ACID” | | Extensions | Exact version, operators/index methods, update scripts | The extension name appears on an allowlist | | Operations | Backup/PITR, CDC, replication, catalogs, monitoring | A backup button exists | | Failure | Node/zone failure, connection convergence, RPO/RTO, rollback | Vendor benchmarks or an SLA number | Run application tests and migrations first, restore a masked production copy next, and rehearse cutover and rollback last. For distributed databases such as CockroachDB and YugabyteDB, deliberately induce transaction conflicts, hot partitions, and node failures. ## Choosing a direction [#choosing-a-direction] * For standard PostgreSQL ecology and minimum migration cost, prefer community PostgreSQL or a managed service that explicitly runs it. * For BaaS choose Supabase; for GraphQL-first choose Nhost; for branches and scale-to-zero evaluate Neon. * For multi-region distributed OLTP, evaluate YugabyteDB and CockroachDB as new databases, not as settings. * For an MPP warehouse, evaluate Cloudberry without extrapolating from OLTP benchmarks. * For Oracle migration, evaluate IvorySQL and preserve separate PostgreSQL-mode and Oracle-mode tests. * For continuously updated views, Materialize is a data-layer candidate, not a transparent primary-OLTP replacement. See [free PostgreSQL cloud databases](/en/docs/cloud/free-postgresql) for free tiers and [PostgreSQL extension selection](/en/docs/reference/extensions-ecosystem) for actual extensions. --- # Version and support policy Canonical URL: https://pg.edu.rich/en/docs/reference/version-policy Last reviewed: 2026-08-02 ## Version meaning [#version-meaning] Since PostgreSQL 10, the first number is the major, such as 18; the dotted number is the minor, such as 18.4. A major arrives roughly yearly with features. A minor contains bug, security, and low-risk fixes. A minor update does not require dump/restore; it usually replaces binaries and restarts, though its release notes still apply. Data directories are incompatible across majors, requiring `pg_upgrade`, logical dump/restore, or logical replication migration. ## Current support snapshot [#current-support-snapshot] As of **2026-08-02**: | Major | Current minor | Status | Final support date | | ----- | ------------: | ------------------- | ------------------ | | 18 | 18.4 | Supported | 2030-11-14 | | 17 | 17.10 | Supported | 2029-11-08 | | 16 | 16.14 | Supported | 2028-11-09 | | 15 | 15.18 | Supported | 2027-11-11 | | 14 | 14.23 | Supported, near EOL | 2026-11-12 | Source: [official PostgreSQL versioning policy](https://www.postgresql.org/support/versioning/). Treat that live page as authoritative. ## Upstream versions are not distribution package versions [#upstream-versions-are-not-distribution-package-versions] ### Sample default postgresql packages across distributions PkgSeek package snapshot; checked: 2026-08-02 15:47:58 UTC. | Distribution | Release | Full version | Repository | Linked advisories | |---|---|---|---|---:| | Alibaba Cloud Linux | 3 | 13.23-3.0.1.al8 | official / updates | 0 | | Alibaba Cloud Linux | 4 | 15.18-1.alnx4 | official / updates | 0 | | AlmaLinux | 10 | 16.14-1.el10_2 | official / AppStream | 0 | | AlmaLinux | 9 | 18.4-2.module_el9.8.0+280+5ad12178 | official / AppStream | 0 | | Arch | rolling | 18.4-3 | official / extra | 0 | | CentOS Stream | 10 | 16.14-1.el10 | official / AppStream | 0 | | CentOS Stream | 9 | 13.23-3.el9 | official / AppStream | 0 | | Debian | trixie | 17+278 | official / main | 3 | | deepin | 25.2 | 16+255 | official / main | 0 | | Fedora | 42 | 16.13-1.fc42 | official / updates | 0 | | Fedora | 43 | 18.3-2.fc43 | official / updates | 0 | | Fedora | 44 | 18.3-2.fc44 | official / updates | 0 | Source: [PkgSeek package lookup](https://pkgseek.com/packages/postgresql). Distribution revisions and backported fixes are part of the complete version identity. Distributions may freeze a major and record packaging revisions or backported security fixes in complete versions such as `16.14-1.el10_2` or `18+290ubuntu1`. Do not decide vulnerability status from the leading `16` or `18` alone. Identify the distribution, release, repository, architecture, and complete package version, then verify the vendor advisory. ## Choosing for a new system [#choosing-for-a-new-system] Default to the latest minor of the latest stable major unless a driver, extension, managed platform, or organizational certification is not ready. A conservative choice is a major with ample support runway that your workload has tested—not a near-EOL version chosen merely because it feels old. PostgreSQL 19 is still in its beta cycle in August 2026 and is not a production default. Test a new major against extensions, collations, backup tools, pools, ORM, plans, and monitoring collectors. See the [PostgreSQL 19 release and 18-to-19 upgrade guide](/en/docs/postgresql-19) for the current Beta status, feature changes, and migration risks. ## Keep the matrix in the repository [#keep-the-matrix-in-the-repository] ```yaml postgresql: supported_majors: [17, 18] tested_minor_floor: 17: 17.10 18: 18.4 extensions: vector: "tested in CI" upgrade_owner: platform-database next_review: 2026-11-01 ``` `latest` is not a deployment strategy. Pin auditable images/packages and let a dependency process advance minors. ## Upgrade principles [#upgrade-principles] * Run the current minor of the chosen major; remaining on an old minor is often riskier than updating. * Read all release notes across the version span. * Test application behavior and plans on a restored real-data copy. * Extensions have separate versions and upgrade scripts; inspect each one. * Refresh statistics and validate backups after a major cutover. --- # Install and connect to PostgreSQL Canonical URL: https://pg.edu.rich/en/docs/setup Last reviewed: 2026-08-02 ## Choose the outcome first [#choose-the-outcome-first] | Outcome | Recommended starting point | | ---------------------------- | --------------------------------------------------------------------------------- | | Learning, tests, CI | Docker: pin the version and remove the whole environment cleanly | | Persistent local development | OS package manager or a trusted installer | | Production | A managed cloud service or team-managed repositories and configuration automation | | Client only | Install `psql`/libpq client packages without running a local server | Do not expose port 5432 publicly or turn `pg_hba.conf` into a global trust rule merely to connect. Verify locally first, then design networking, TLS, authentication, and least privilege. ## Run the same verification everywhere [#run-the-same-verification-everywhere] ```bash psql --version psql -X "postgresql://postgres@localhost:5432/postgres" \ -c "select current_setting('server_version'), current_database(), current_user;" ``` Client and server versions are separate. `psql --version` reports only the client; the SQL query reports the server you actually reached. When versions coexist, record executable path, port, and data directory. Next, read [`psql` connections and SSL](/en/docs/setup/psql-connection), then create an application role that is not a superuser. --- # PostgreSQL Linux packages, versions, and PGDG Canonical URL: https://pg.edu.rich/en/docs/setup/linux-packages Last reviewed: 2026-08-02 “Install PostgreSQL on Linux” is not one stable command. The distribution, release, repository source, CPU architecture, and package name jointly determine the installed major, packaging revision, and security fixes. This page combines changing package evidence from [PkgSeek](https://pkgseek.com/packages/postgresql) with this guide's installation and upgrade rules. ### Default postgresql packages across Linux distributions PkgSeek package snapshot; checked: 2026-08-02 15:47:58 UTC. | Distribution | Release | Full version | Repository | Linked advisories | |---|---|---|---|---:| | Alibaba Cloud Linux | 3 | 13.23-3.0.1.al8 | official / updates | 0 | | Alibaba Cloud Linux | 4 | 15.18-1.alnx4 | official / updates | 0 | | AlmaLinux | 10 | 16.14-1.el10_2 | official / AppStream | 0 | | AlmaLinux | 9 | 18.4-2.module_el9.8.0+280+5ad12178 | official / AppStream | 0 | | Arch | rolling | 18.4-3 | official / extra | 0 | | CentOS Stream | 10 | 16.14-1.el10 | official / AppStream | 0 | | CentOS Stream | 9 | 13.23-3.el9 | official / AppStream | 0 | | Debian | trixie | 17+278 | official / main | 3 | | deepin | 25.2 | 16+255 | official / main | 0 | | Fedora | 42 | 16.13-1.fc42 | official / updates | 0 | | Fedora | 43 | 18.3-2.fc43 | official / updates | 0 | | Fedora | 44 | 18.3-2.fc44 | official / updates | 0 | | Kali Linux | kali-rolling | 18+290 | official / main | 0 | | Kylin OS | V10-SP1 | 12+214kylin0.1 | official / 10.1-main | 0 | | Kylin OS Server | V10-SP3-2403 | 10.5-23.p09.ky10 | official / updates | 0 | | OpenAnolis | 23.4 | 15.18-1.an23 | official / updates | 0 | | OpenAnolis | 8.10 | 12.22-7.0.1.module+an8.10.0+11420+6683745d | official / AppStream | 0 | | openEuler | 24.03-LTS-SP4 | 15.18-1.oe2403sp4 | official / everything | 0 | | openSUSE | 15.6 | 18-150600.17.9.1 | official / update-sle | 0 | | openSUSE | tumbleweed | 18-3.4 | official / oss | 0 | | Oracle Linux | 10 | 16.14-1.0.1.el10_2 | official / appstream | 0 | | Oracle Linux | 8 | 12.22-6.0.1.module+el8.10.0+90932+f6d78e3c | official / appstream | 34 | | Oracle Linux | 9 | 13.23-3.el9_8 | official / appstream | 26 | | Raspberry Pi OS | bookworm | 15+248+deb12u1 | official / bookworm-main | 0 | | Raspberry Pi OS | trixie | 17+278 | official / trixie-main | 0 | | Red Hat Enterprise Linux | 10.2 | 16.14-1.el10_2 | official / AppStream | 0 | | Red Hat Enterprise Linux | 9.8 | 18.4-2.module+el9.8.0+24359+da7fad50 | official / AppStream | 0 | | Rocky Linux | 10 | 16.14-1.el10_2 | official / AppStream | 0 | | Rocky Linux | 9 | 13.23-3.el9_8 | official / AppStream | 13 | | Ubuntu | focal | 12+214 | official / main | 0 | | Ubuntu | jammy | 14+238 | official / main | 0 | | Ubuntu | noble | 16+257build1 | official / main | 0 | | Ubuntu | resolute | 18+290ubuntu1 | official / main | 0 | | Void Linux | rolling | 18_1 | official / current | 0 | Source: [PkgSeek package lookup](https://pkgseek.com/packages/postgresql). Distribution revisions and backported fixes are part of the complete version identity. ## Distinguish four package families [#distinguish-four-package-families] | Family | Common examples | Meaning | | ------------------------ | ------------------------------------------------------- | -------------------------------------------------------------------- | | Distribution metapackage | `postgresql` | Follows the major selected by that distribution release | | Versioned server | `postgresql-18`, `postgresql18-server` | Pins a major; naming differs between DEB and RPM ecosystems | | Client and development | `postgresql-client-18`, `libpq-dev`, `postgresql-devel` | Provides `psql`, libpq headers, or build files; may not run a server | | Extension | `postgresql-18-pgvector`, `pgvector` | Must also match server major, architecture, and extension version | Similar names do not prove identical roles. Verify the client and server separately after installation: ```bash psql --version sudo -u postgres psql -X -d postgres \ -c "select version(), current_setting('server_version_num');" ``` ## Distribution repositories and PGDG [#distribution-repositories-and-pgdg] Distribution repositories generally maintain a selected major. The [PostgreSQL Global Development Group repositories](https://www.postgresql.org/download/linux/) are commonly used for other supported majors. Adding PGDG creates an external software-source dependency, so record repository signing, release support, upgrade policy, and an exit path. ### postgresql-18 in Ubuntu repositories PkgSeek package snapshot; checked: 2026-08-02 15:47:58 UTC. | Distribution | Release | Full version | Repository | Linked advisories | |---|---|---|---|---:| | Ubuntu | resolute | 18.3-1 | official / main | — | Source: [PkgSeek package lookup](https://pkgseek.com/packages/postgresql-18). Distribution revisions and backported fixes are part of the complete version identity. ### postgresql-18 in Ubuntu PGDG PkgSeek package snapshot; checked: 2026-08-02 15:47:58 UTC. > No exact indexed coordinate. This means the current snapshot has no match, not that the package does not exist. Source: [PkgSeek package lookup](https://pkgseek.com/search?q=postgresql-18). Distribution revisions and backported fixes are part of the complete version identity. The tables query exact coordinates in the Ubuntu and PGDG repositories separately. If a card reports “no exact indexed coordinate”, that describes index coverage, not the target repository's contents. Use the target system's `apt-cache policy` and official PostgreSQL repository instructions as the final installation evidence. ```bash apt-cache policy postgresql postgresql-18 postgresql-client-18 apt-cache madison postgresql-18 ``` ## Track PostgreSQL 19 packages [#track-postgresql-19-packages] ### postgresql-19 in distribution repositories PkgSeek package snapshot; checked: 2026-08-02 15:47:58 UTC. > No exact indexed coordinate. This means the current snapshot has no match, not that the package does not exist. Source: [PkgSeek package lookup](https://pkgseek.com/search?q=postgresql-19). Distribution revisions and backported fixes are part of the complete version identity. A missing stable distribution package is expected while PostgreSQL 19 remains in beta. Even after a test build appears, keep the beta compatibility lane separate from production PostgreSQL 18. Use the [PostgreSQL 18-to-19 upgrade guide](/en/docs/postgresql-19) for adoption criteria. ## Use package evidence safely [#use-package-evidence-safely] 1. Record `distro + release + source + repository + architecture + full version`. 2. Determine whether a package contains the server, client, development files, or an extension. 3. For CVEs, prioritize distribution advisories and backport status over an upstream version prefix. 4. After installation, verify the connected server; `psql --version` only identifies the client. 5. A major change requires `pg_upgrade`, dump/restore, or logical replication. Replacing a package does not upgrade a data directory. Package indexes have coverage and refresh boundaries. When this page reports “no exact indexed coordinate”, continue with the upstream repository; do not let a person or model turn an empty array into a definitive answer. ## Minimum contract for an AI agent [#minimum-contract-for-an-ai-agent] ```yaml task: resolve_postgresql_package target: distro: ubuntu release: noble architecture: amd64 source: pgdg requirements: - return exact package coordinates and observed_at - separate indexed fact, inference, and unknown - never interpret missing index data as package absence - ask before repository, package, service, or data changes - verify client and server versions after execution ``` PkgSeek publishes a [read-only MCP tool catalogue](https://pkgseek.com/mcp/tools) and an [OpenAPI 3.1 specification](https://pkgseek.com/openapi.json). See the [AI context contract](/en/docs/ai/context-contract) for the execution boundary. --- # Install PostgreSQL 18 on macOS Canonical URL: https://pg.edu.rich/en/docs/setup/macos Last reviewed: 2026-08-02 The [PostgreSQL macOS download page](https://www.postgresql.org/download/macosx/) lists three common paths: the EDB graphical installer, Postgres.app, and Homebrew. Do not run several installations on port 5432 accidentally; choose one and record its data directory. ## Homebrew [#homebrew] ```bash brew update brew install postgresql@18 brew services start postgresql@18 "$(brew --prefix postgresql@18)/bin/psql" --version ``` Homebrew may not place a versioned client in the default `PATH`. For a persistent shell setup, follow the path printed by `brew info postgresql@18` instead of copying a Cellar path that can change on upgrade. Verify the connection: ```bash "$(brew --prefix postgresql@18)/bin/psql" -X -d postgres \ -c "select version(), current_setting('data_directory');" ``` Use `-U` and `-d` when your local role or database differs. ## Postgres.app or graphical installer [#postgresapp-or-graphical-installer] * Postgres.app fits local developers who want menu-bar start/stop with little system configuration. * The EDB installer includes the server, pgAdmin, and StackBuilder for a guided graphical setup. After installation, do not rely on an icon alone. Run this through the bundled `psql`: ```sql SELECT version(), current_database(), current_user; ``` Confirm that the package or Homebrew prefix matches arm64/amd64. Do not copy a data directory across architectures; prefer logical backup or a tested upgrade path. ## Diagnose multiple versions [#diagnose-multiple-versions] ```bash which -a psql psql --version lsof -nP -iTCP:5432 -sTCP:LISTEN ``` A client/server version difference does not automatically require reinstalling. Confirm the actual target first; a client no older than the server is generally the safer choice. --- # Connect to PostgreSQL with psql and SSL Canonical URL: https://pg.edu.rich/en/docs/setup/psql-connection Last reviewed: 2026-08-02 ## State all five connection dimensions [#state-all-five-connection-dimensions] ```bash psql -X \ --host=db.example.com \ --port=5432 \ --username=app_reader \ --dbname=commerce ``` Host, port, database, user, and TLS parameters identify the target together. A database name alone is insufficient; many instances can contain the same name. Equivalent connection URI: ```bash psql -X "postgresql://app_reader@db.example.com:5432/commerce?sslmode=verify-full" ``` Do not place passwords in command-line URIs, source code, or logs. Use an interactive prompt, secret manager, short-lived identity, `.pgpass`, or a libpq service file. ## pgpass [#pgpass] The Unix default is `~/.pgpass`, restricted to mode `0600`: ```text hostname:5432:database:username:password ``` ```bash chmod 600 ~/.pgpass ``` The Windows default is `%APPDATA%\postgresql\pgpass.conf`. Wildcards broaden where a credential applies; prefer a specific host, database, and user. ## SSL modes [#ssl-modes] | `sslmode` | Behavior | Guidance | | ------------- | ----------------------------------------------- | ------------------------------------------------------------ | | `disable` | No TLS | Controlled local or isolated testing only | | `require` | Encrypts without complete identity verification | Better than plaintext, insufficient against a wrong endpoint | | `verify-ca` | Verifies the certificate chain | Does not verify hostname | | `verify-full` | Verifies chain and hostname | Target for remote production connections | `verify-full` requires the URI host to match the certificate identity and a correct root certificate. Cloud providers can have CA rotation workflows; do not pin an expired certificate forever. ## Confirm immediately after connecting [#confirm-immediately-after-connecting] ```sql \conninfo SELECT current_database(), current_user, session_user, inet_server_addr(), inet_server_port(), current_setting('server_version') AS server_version, current_setting('TimeZone') AS timezone; ``` For scripts: ```bash psql -X --set ON_ERROR_STOP=on --file migration.sql "$DATABASE_URL" ``` `-X` prevents a user's `.psqlrc` from changing automation; `ON_ERROR_STOP` exits on SQL errors. See the [PostgreSQL 18 psql documentation](https://www.postgresql.org/docs/18/app-psql.html) for exit-status semantics. Connection parameters bound session establishment; `statement_timeout` bounds SQL execution; `lock_timeout` only bounds lock waiting. The application also needs a request deadline and must cancel or release the database connection after timeout. On failure, retain the full error and SQLSTATE, then use the [error fieldbook](/en/docs/reference/errors). Do not troubleshoot by disabling TLS or broadening privileges. --- # Install PostgreSQL 18 on Ubuntu Canonical URL: https://pg.edu.rich/en/docs/setup/ubuntu Last reviewed: 2026-08-02 Ubuntu includes PostgreSQL, but the major version is fixed by the Ubuntu release snapshot. If that maintained default is acceptable: ```bash sudo apt update sudo apt install postgresql postgresql-client ``` ### Ubuntu default postgresql metapackage PkgSeek package snapshot; checked: 2026-08-02 15:47:58 UTC. | Distribution | Release | Full version | Repository | Linked advisories | |---|---|---|---|---:| | Ubuntu | focal | 12+214 | official / main | — | | Ubuntu | jammy | 14+238 | official / main | — | | Ubuntu | noble | 16+257build1 | official / main | — | | Ubuntu | resolute | 18+290ubuntu1 | official / main | — | Source: [PkgSeek package lookup](https://pkgseek.com/packages/postgresql). Distribution revisions and backported fixes are part of the complete version identity. The snapshot shows that the default major changes between Ubuntu releases. `postgresql` follows the distribution; it does not always install PostgreSQL 18. See [Linux packages and PGDG](/en/docs/setup/linux-packages) for the complete boundary. ## Install PostgreSQL 18 explicitly [#install-postgresql-18-explicitly] For a specific major, use the Apt repository maintained by the PostgreSQL project. Its automated setup path is: ```bash sudo apt install -y postgresql-common ca-certificates sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh sudo apt update sudo apt install postgresql-18 postgresql-client-18 ``` Read the script output and confirm that your OS release is supported. Treat the [PostgreSQL Ubuntu download page](https://www.postgresql.org/download/linux/ubuntu/) as authoritative for current commands and releases. ### PkgSeek: Ubuntu / PGDG / postgresql-18 PkgSeek package snapshot; checked: 2026-08-02 15:47:58 UTC. > No exact indexed coordinate. This means the current snapshot has no match, not that the package does not exist. Source: [PkgSeek package lookup](https://pkgseek.com/search?q=postgresql-18). Distribution revisions and backported fixes are part of the complete version identity. If the card does not return an exact PGDG coordinate, the empty result cannot prove that the package is unavailable. Confirm against PGDG repository metadata and the official PostgreSQL download page. The documentation keeps the gap visible instead of filling it with an assumption. ## Verify service and cluster [#verify-service-and-cluster] ```bash systemctl status postgresql --no-pager pg_lsclusters sudo -u postgres psql -X -d postgres \ -c "select version(), current_setting('data_directory');" ``` `postgresql.service` is the cluster-management entry point; a concrete instance commonly appears as `postgresql@18-main`. `pg_lsclusters` belongs to Debian/Ubuntu `postgresql-common`, not every Linux distribution. Create a local practice role and database: ```bash sudo -u postgres createuser --pwprompt learner sudo -u postgres createdb --owner=learner learner psql -X -h localhost -U learner -d learner -c "select current_user;" ``` Remote access involves `listen_addresses`, `pg_hba.conf`, firewall rules, and TLS together. Save the original configuration, start with a specific network/database/role rule, and test both allowed and denied paths. ## Upgrade boundary [#upgrade-boundary] `apt upgrade` can install minor fixes inside one major. Moving from 17 to 18 is a major upgrade requiring `pg_upgrade`, logical dump/restore, or logical replication; replacing packages does not make an old data directory compatible. --- # Install PostgreSQL 18 on Windows Canonical URL: https://pg.edu.rich/en/docs/setup/windows Last reviewed: 2026-08-02 The PostgreSQL project links the EDB-certified interactive installer from its [Windows download page](https://www.postgresql.org/download/windows/). The bundle commonly includes the PostgreSQL server, pgAdmin, and StackBuilder. ## Record during installation [#record-during-installation] * major version and install directory; * data directory, outside folders controlled by consumer sync tools; * PostgreSQL service account; * listening port, commonly 5432; * the `postgres` administrator password, stored in a password manager; * locale, with collation behavior tested before production migration. Select only components you need. Extra drivers and extensions in StackBuilder are not PostgreSQL core and should follow project requirements. ## Verify with psql [#verify-with-psql] Open the SQL Shell installed with PostgreSQL, or add its `bin` directory to the current terminal path: ```powershell psql.exe --version psql.exe -X -h localhost -p 5432 -U postgres -d postgres ` -c "select version(), current_database(), current_user;" ``` Inspect the service through Windows Services or PowerShell: ```powershell Get-Service *postgres* ``` If the client is missing, locate `psql.exe` in the installation directory; do not download standalone DLLs from an unknown source. ## Common connection failures [#common-connection-failures] | Symptom | Check first | | ------------------------------ | -------------------------------------------------------------------- | | connection refused | Whether the PostgreSQL service is running and the port is correct | | password authentication failed | Username, target instance, password, and matching `pg_hba.conf` rule | | database does not exist | Whether the database passed with `-d` was created | | unexpected server version | Whether several PostgreSQL services are running on Windows | Local development normally needs no inbound firewall opening. Remote access must restrict source addresses and use appropriate TLS validation. Do not replace diagnosis with a passwordless `trust` rule in `pg_hba.conf`. ## Before uninstalling [#before-uninstalling] Removing software and deleting the data directory are separate operations. Export required content with `pg_dump` plus `pg_dumpall --globals-only`, test a restore, and confirm the exact data directory before deletion.