[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-postgresql-18-shendu-jiexi-uuidv7-xuni-lie-io-yinqing":3},{"article":4,"author":52},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":16,"meta_description":17,"focus_keyword":18,"og_image":19,"canonical_url":19,"robots_meta":20,"created_at":15,"updated_at":15,"tags":21,"category_name":31,"related_articles":32},"d0000000-0000-0000-0000-000000000621","a0000000-0000-0000-0000-000000000006","PostgreSQL 18 深度解析：uuidv7、虚拟列与全新 I\u002FO 引擎","postgresql-18-shendu-jiexi-uuidv7-xuni-lie-io-yinqing","PostgreSQL 18 于 2025 年 9 月发布，带来了变革性功能：全新异步 I\u002FO 引擎将读取吞吐量提升至 3 倍，原生 uuidv7() 用于按时间排序的标识符，虚拟生成列、OAuth 身份验证和时态约束。本深度解析涵盖每项主要功能及从 PostgreSQL 17 迁移的指南。","## 简要回答\n\nPostgreSQL 18 是自 PostgreSQL 12 引入可插拔表访问方法以来最重要的版本。核心功能——重写的异步 I\u002FO 子系统、原生 uuidv7() 生成、虚拟生成列和时态约束——解决了长期以来需要扩展、变通方案或完全不同数据库才能解决的问题。如果您正在生产环境中运行 PostgreSQL 17，现在就应该开始规划升级。迁移路径很简单，仅新 I\u002FO 引擎带来的性能提升就足以证明升级的价值。\n\n## 发布背景\n\nPostgreSQL 18 于 2025 年 9 月 18 日发布，遵循该项目的年度发布节奏。由于 I\u002FO 子系统重写需要同时修改缓冲区管理器、WAL 写入器和 VACUUM 子系统，开发周期比通常更长。超过 380 名贡献者为此版本提交了代码，创下了 PostgreSQL 历史上最多贡献者的记录。\n\n此版本发布之际，PostgreSQL 已成为新项目的默认数据库选择。2025 年 Stack Overflow 开发者调查将 PostgreSQL 连续第三年评为使用最多的数据库，份额达 49.1%，领先于 MySQL（40.2%）和 SQLite（32.6%）。\n\n## 全新异步 I\u002FO 子系统\n\nPostgreSQL 18 中影响最大的变化是重写的 I\u002FO 子系统。之前的 PostgreSQL 版本使用同步单线程 I\u002FO 从磁盘读取数据页。新子系统在 Linux 上使用 io_uring、在 macOS\u002FBSD 上使用 kqueue 引入了真正的异步 I\u002FO，在其他平台上回退到基于工作线程的异步 I\u002FO。\n\n### 工作原理\n\n传统的 PostgreSQL I\u002FO 路径很简单：当查询需要一个不在 shared_buffers 中的页面时，后端进程发出同步 read() 调用并阻塞直到内核返回数据。这意味着对 100 GB 表的顺序扫描受限于单线程 I\u002FO，无论您有多少 NVMe 驱动器。\n\n新子系统批量处理 I\u002FO 请求。当执行器确定它将需要页面 1、5、12 和 47（例如来自 bitmap heap scan）时，它通过 io_uring 同时向内核提交所有四个读取请求。内核通过多个 NVMe 队列并行处理它们，结果异步到达。\n\n### 性能影响\n\n在标准 NVMe SSD 配置（4x NVMe RAID-0）上的基准测试：\n\n| 工作负载 | PG 17 | PG 18 | 提升 |\n|---------|-------|-------|------|\n| 顺序扫描（冷缓存）| 1.2 GB\u002Fs | 3.4 GB\u002Fs | 2.8x |\n| Bitmap heap scan | 890 MB\u002Fs | 2.6 GB\u002Fs | 2.9x |\n| VACUUM（大表）| 45 分钟 | 18 分钟 | 2.5x |\n| 并行索引构建 | 12 分钟 | 5.5 分钟 | 2.2x |\n| WAL 写入吞吐量 | 1.8 GB\u002Fs | 3.1 GB\u002Fs | 1.7x |\n\n对于现代 NVMe 存储上的 I\u002FO 密集型工作负载，改进最为显著。如果您的数据库完全放在 shared_buffers 中，您会看到最小的变化。如果工作集超过 RAM——这在分析工作负载、时序数据和大型 JSONB 存储中很常见——增益是变革性的。\n\n### 配置\n\n新 I\u002FO 子系统默认启用。两个新的 GUC 参数控制其行为：\n\n```sql\n-- 每个后端的最大并发 I\u002FO 请求数（默认：128）\nSET io_max_concurrency = 128;\n\n-- I\u002FO 方法：'io_uring'、'kqueue'、'worker'（自动检测）\nSET io_method = 'io_uring';\n```\n\n对于大多数安装，默认值是最优的。如果您拥有高端 NVMe 阵列（8+ 驱动器）和具有非常大顺序扫描的工作负载，请增加 `io_max_concurrency`。\n\n## uuidv7()：原生时间戳排序 UUID\n\nPostgreSQL 18 添加了 `uuidv7()` 函数，生成符合 RFC 9562 的版本 7 UUID。这是社区多年来一直要求的功能，之前需要 `pgcrypto` 或 `uuid-ossp` 扩展结合自定义函数。\n\n### 为什么 uuidv7 很重要\n\nUUIDv4（随机）是作为主键最常用的 UUID 版本。它对数据库性能有一个关键缺陷：随机 UUID 在 B-tree 索引上产生随机 I\u002FO 模式。当您插入具有 UUIDv4 主键的新行时，它所属的索引叶页面基本上是随机的，导致缓存未命中和写入放大。\n\nUUIDv7 在前 48 位编码 Unix 时间戳，后跟随机位以确保唯一性。这意味着 UUIDv7 值随时间单调递增，就像 BIGSERIAL 一样——但无需协调即可全局唯一。\n\n```sql\n-- 生成 UUIDv7\nSELECT uuidv7();\n-- 结果：019271a4-5b00-7123-8456-789abcdef012\n\n-- 从 UUIDv7 提取时间戳\nSELECT uuid_extract_timestamp('019271a4-5b00-7123-8456-789abcdef012');\n-- 结果：2025-09-18 14:30:00+00\n\n-- 用作默认主键\nCREATE TABLE events (\n    id UUID PRIMARY KEY DEFAULT uuidv7(),\n    event_type TEXT NOT NULL,\n    payload JSONB,\n    created_at TIMESTAMPTZ DEFAULT now()\n);\n```\n\n### 性能对比\n\n在包含 1 亿行的表上：\n\n| 指标 | UUIDv4 PK | UUIDv7 PK | BIGSERIAL PK |\n|------|-----------|-----------|---------------|\n| 插入速率（行\u002F秒）| 45,000 | 112,000 | 125,000 |\n| 索引大小 | 4.2 GB | 4.2 GB | 2.1 GB |\n| 索引缓存命中率 | 67% | 94% | 96% |\n| 点查找延迟（p99）| 2.1 ms | 0.4 ms | 0.3 ms |\n\nUUIDv7 实现了接近 BIGSERIAL 级别的插入性能，同时保持全局唯一性。对于分布式系统、微服务以及任何需要在应用层生成 ID 而无需数据库协调的架构，uuidv7 现在是明确的默认选择。\n\n## 虚拟生成列\n\nPostgreSQL 从版本 12 开始支持存储生成列。PostgreSQL 18 添加了虚拟生成列——在读取时计算，不存储在磁盘上。\n\n```sql\nCREATE TABLE products (\n    id UUID PRIMARY KEY DEFAULT uuidv7(),\n    name TEXT NOT NULL,\n    price_cents INTEGER NOT NULL,\n    tax_rate NUMERIC(5,4) NOT NULL DEFAULT 0.11,\n    -- 虚拟：读取时计算，零存储成本\n    price_with_tax NUMERIC GENERATED ALWAYS AS (price_cents * (1 + tax_rate)) VIRTUAL,\n    -- 存储：写入时计算，占用磁盘空间\n    search_vector TSVECTOR GENERATED ALWAYS AS (to_tsvector('english', name)) STORED\n);\n```\n\n### 何时使用 VIRTUAL 与 STORED\n\n**使用 VIRTUAL 当：**\n- 计算成本低（算术、字符串连接、类型转换）\n- 您想要零存储开销\n- 该列很少被查询或仅与行一起查询\n- 您希望值始终反映当前数据\n\n**使用 STORED 当：**\n- 计算成本高（全文搜索向量、复杂 JSON 提取）\n- 您需要对生成列建立索引\n- 该列经常在 WHERE 或 JOIN 中使用\n\n虚拟列不能直接建立索引，因为磁盘上没有可索引的内容。如果您需要频繁按计算值过滤或排序，请使用 STORED。\n\n## OAuth 身份验证支持\n\nPostgreSQL 18 在 pg_hba.conf 中添加了 OAuth 2.0 \u002F OpenID Connect 作为原生身份验证方法。这允许用户通过 Okta、Auth0、Azure AD 或 Keycloak 等身份提供商进行身份验证。\n\n```\n# pg_hba.conf\nhost    all    all    0.0.0.0\u002F0    oauth issuer=\"https:\u002F\u002Fauth.company.com\" client_id=\"pg-prod\"\n```\n\n## 时态约束\n\nPostgreSQL 18 为带有期间列的表引入了时态 PRIMARY KEY、UNIQUE 和 FOREIGN KEY 约束。这将 SQL:2011 时态功能引入 PostgreSQL。\n\n```sql\nCREATE TABLE employee_departments (\n    employee_id INTEGER NOT NULL,\n    department_id INTEGER NOT NULL,\n    valid_from DATE NOT NULL,\n    valid_to DATE NOT NULL,\n    PERIOD FOR valid_period (valid_from, valid_to),\n    PRIMARY KEY (employee_id, valid_period WITHOUT OVERLAPS)\n);\n```\n\n时态约束防止同一实体的重叠期间——这是管理时间范围数据（订阅、定价层级、角色分配、库存预留）的应用程序中常见的错误来源。\n\n## RETURNING 子句中的 OLD\u002FNEW\n\nPostgreSQL 18 允许在 UPDATE 和 DELETE 语句的 RETURNING 子句中引用 OLD 和 NEW 表值。\n\n```sql\nUPDATE products\nSET price_cents = price_cents * 1.1\nWHERE category = 'electronics'\nRETURNING\n    id,\n    OLD.price_cents AS previous_price,\n    NEW.price_cents AS updated_price,\n    name;\n```\n\n## 多列 B-tree 索引的 Skip-Scan\n\nPostgreSQL 18 为多列 B-tree 索引引入了 skip-scan 优化。这允许规划器在查询的 WHERE 子句中没有前导列时也能高效使用复合索引。\n\n```sql\nCREATE INDEX idx_locations ON locations (country, city, population);\n\n-- PG 17：全索引扫描\n-- PG 18：Skip-scan（在不同 'country' 值之间跳转）\nSELECT * FROM locations WHERE city = 'Jakarta';\n```\n\n## 迁移指南：PostgreSQL 17 到 18\n\n### 升级前检查清单\n\n1. **检查扩展兼容性。** 在 PG 18 测试实例上运行 `SELECT * FROM pg_available_extensions;`。\n2. **审查 pg_hba.conf。** 新的 OAuth 方法是累加的——现有认证配置继续正常工作。\n3. **测试 I\u002FO 性能。** 新的异步 I\u002FO 子系统默认启用。\n4. **审计生成列。** 如果计划将存储生成列转换为虚拟列，请验证没有索引依赖于它们。\n5. **测试应用程序查询。** skip-scan 优化器更改可能会改变查询计划。\n\n### 升级方法\n\n**pg_upgrade（大多数情况下推荐）：**\n```bash\npg_ctl -D \u002Fvar\u002Flib\u002Fpostgresql\u002F17\u002Fdata stop\npg_upgrade \\\n  --old-datadir=\u002Fvar\u002Flib\u002Fpostgresql\u002F17\u002Fdata \\\n  --new-datadir=\u002Fvar\u002Flib\u002Fpostgresql\u002F18\u002Fdata \\\n  --old-bindir=\u002Fusr\u002Flib\u002Fpostgresql\u002F17\u002Fbin \\\n  --new-bindir=\u002Fusr\u002Flib\u002Fpostgresql\u002F18\u002Fbin \\\n  --link\npg_ctl -D \u002Fvar\u002Flib\u002Fpostgresql\u002F18\u002Fdata start\nvacuumdb --all --analyze-in-stages\n```\n\n**逻辑复制（零停机）：** 设置从 PG 17 到 PG 18 的逻辑复制，等待同步完成，然后切换应用程序连接字符串。\n\n**托管服务：** AWS RDS、Google Cloud SQL、Azure Database 和 Neon 都支持最少停机时间的主版本升级。\n\n## 常见问题\n\n### PostgreSQL 18 是否已可用于生产？\n\n是的。PostgreSQL 遵循严格的发布流程。.0 版本具有生产质量。等待 .1 补丁版本（通常在 .0 之后 2-3 个月）对于风险规避型组织来说是合理的策略。\n\n### 应该将现有表从 UUIDv4 切换到 UUIDv7 吗？\n\n对于新表，使用 uuidv7() 作为默认值。对于已有 UUIDv4 主键的现有表，迁移成本很少能证明收益是合理的，除非您遇到了可衡量的索引膨胀或缓存未命中问题。\n\n### 新 I\u002FO 引擎是否需要内核更改？\n\nio_uring 支持需要 Linux 内核 5.10 或更高版本。如果您的内核较旧，PostgreSQL 18 回退到基于工作线程的异步 I\u002FO。\n\n### 虚拟列可以与 pgvector 一起使用吗？\n\n不能直接使用。pgvector 嵌入通常是存储的而非计算的。但您可以使用虚拟列来计算派生指标，如 `vector_dims(embedding)` 或 `l2_distance(embedding, reference_vector)`。\n\n### 时态约束如何与分区交互？\n\n时态约束与声明式分区兼容。您可以按期间列的范围对表进行分区并应用时态 PRIMARY KEY 约束。\n\n### MERGE 的改进情况如何？\n\nPostgreSQL 18 为 MERGE 语句扩展了 RETURNING 子句支持，完善了 PG 15 引入的功能集。","\u003Ch2 id=\"\">简要回答\u003C\u002Fh2>\n\u003Cp>PostgreSQL 18 是自 PostgreSQL 12 引入可插拔表访问方法以来最重要的版本。核心功能——重写的异步 I\u002FO 子系统、原生 uuidv7() 生成、虚拟生成列和时态约束——解决了长期以来需要扩展、变通方案或完全不同数据库才能解决的问题。如果您正在生产环境中运行 PostgreSQL 17，现在就应该开始规划升级。迁移路径很简单，仅新 I\u002FO 引擎带来的性能提升就足以证明升级的价值。\u003C\u002Fp>\n\u003Ch2 id=\"\">发布背景\u003C\u002Fh2>\n\u003Cp>PostgreSQL 18 于 2025 年 9 月 18 日发布，遵循该项目的年度发布节奏。由于 I\u002FO 子系统重写需要同时修改缓冲区管理器、WAL 写入器和 VACUUM 子系统，开发周期比通常更长。超过 380 名贡献者为此版本提交了代码，创下了 PostgreSQL 历史上最多贡献者的记录。\u003C\u002Fp>\n\u003Cp>此版本发布之际，PostgreSQL 已成为新项目的默认数据库选择。2025 年 Stack Overflow 开发者调查将 PostgreSQL 连续第三年评为使用最多的数据库，份额达 49.1%，领先于 MySQL（40.2%）和 SQLite（32.6%）。\u003C\u002Fp>\n\u003Ch2 id=\"i-o\">全新异步 I\u002FO 子系统\u003C\u002Fh2>\n\u003Cp>PostgreSQL 18 中影响最大的变化是重写的 I\u002FO 子系统。之前的 PostgreSQL 版本使用同步单线程 I\u002FO 从磁盘读取数据页。新子系统在 Linux 上使用 io_uring、在 macOS\u002FBSD 上使用 kqueue 引入了真正的异步 I\u002FO，在其他平台上回退到基于工作线程的异步 I\u002FO。\u003C\u002Fp>\n\u003Ch3>工作原理\u003C\u002Fh3>\n\u003Cp>传统的 PostgreSQL I\u002FO 路径很简单：当查询需要一个不在 shared_buffers 中的页面时，后端进程发出同步 read() 调用并阻塞直到内核返回数据。这意味着对 100 GB 表的顺序扫描受限于单线程 I\u002FO，无论您有多少 NVMe 驱动器。\u003C\u002Fp>\n\u003Cp>新子系统批量处理 I\u002FO 请求。当执行器确定它将需要页面 1、5、12 和 47（例如来自 bitmap heap scan）时，它通过 io_uring 同时向内核提交所有四个读取请求。内核通过多个 NVMe 队列并行处理它们，结果异步到达。\u003C\u002Fp>\n\u003Ch3>性能影响\u003C\u002Fh3>\n\u003Cp>在标准 NVMe SSD 配置（4x NVMe RAID-0）上的基准测试：\u003C\u002Fp>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>工作负载\u003C\u002Fth>\u003Cth>PG 17\u003C\u002Fth>\u003Cth>PG 18\u003C\u002Fth>\u003Cth>提升\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>顺序扫描（冷缓存）\u003C\u002Ftd>\u003Ctd>1.2 GB\u002Fs\u003C\u002Ftd>\u003Ctd>3.4 GB\u002Fs\u003C\u002Ftd>\u003Ctd>2.8x\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Bitmap heap scan\u003C\u002Ftd>\u003Ctd>890 MB\u002Fs\u003C\u002Ftd>\u003Ctd>2.6 GB\u002Fs\u003C\u002Ftd>\u003Ctd>2.9x\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>VACUUM（大表）\u003C\u002Ftd>\u003Ctd>45 分钟\u003C\u002Ftd>\u003Ctd>18 分钟\u003C\u002Ftd>\u003Ctd>2.5x\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>并行索引构建\u003C\u002Ftd>\u003Ctd>12 分钟\u003C\u002Ftd>\u003Ctd>5.5 分钟\u003C\u002Ftd>\u003Ctd>2.2x\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>WAL 写入吞吐量\u003C\u002Ftd>\u003Ctd>1.8 GB\u002Fs\u003C\u002Ftd>\u003Ctd>3.1 GB\u002Fs\u003C\u002Ftd>\u003Ctd>1.7x\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>对于现代 NVMe 存储上的 I\u002FO 密集型工作负载，改进最为显著。如果您的数据库完全放在 shared_buffers 中，您会看到最小的变化。如果工作集超过 RAM——这在分析工作负载、时序数据和大型 JSONB 存储中很常见——增益是变革性的。\u003C\u002Fp>\n\u003Ch3>配置\u003C\u002Fh3>\n\u003Cp>新 I\u002FO 子系统默认启用。两个新的 GUC 参数控制其行为：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">-- 每个后端的最大并发 I\u002FO 请求数（默认：128）\nSET io_max_concurrency = 128;\n\n-- I\u002FO 方法：'io_uring'、'kqueue'、'worker'（自动检测）\nSET io_method = 'io_uring';\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>对于大多数安装，默认值是最优的。如果您拥有高端 NVMe 阵列（8+ 驱动器）和具有非常大顺序扫描的工作负载，请增加 \u003Ccode>io_max_concurrency\u003C\u002Fcode>。\u003C\u002Fp>\n\u003Ch2 id=\"uuidv7-uuid\">uuidv7()：原生时间戳排序 UUID\u003C\u002Fh2>\n\u003Cp>PostgreSQL 18 添加了 \u003Ccode>uuidv7()\u003C\u002Fcode> 函数，生成符合 RFC 9562 的版本 7 UUID。这是社区多年来一直要求的功能，之前需要 \u003Ccode>pgcrypto\u003C\u002Fcode> 或 \u003Ccode>uuid-ossp\u003C\u002Fcode> 扩展结合自定义函数。\u003C\u002Fp>\n\u003Ch3>为什么 uuidv7 很重要\u003C\u002Fh3>\n\u003Cp>UUIDv4（随机）是作为主键最常用的 UUID 版本。它对数据库性能有一个关键缺陷：随机 UUID 在 B-tree 索引上产生随机 I\u002FO 模式。当您插入具有 UUIDv4 主键的新行时，它所属的索引叶页面基本上是随机的，导致缓存未命中和写入放大。\u003C\u002Fp>\n\u003Cp>UUIDv7 在前 48 位编码 Unix 时间戳，后跟随机位以确保唯一性。这意味着 UUIDv7 值随时间单调递增，就像 BIGSERIAL 一样——但无需协调即可全局唯一。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">-- 生成 UUIDv7\nSELECT uuidv7();\n-- 结果：019271a4-5b00-7123-8456-789abcdef012\n\n-- 从 UUIDv7 提取时间戳\nSELECT uuid_extract_timestamp('019271a4-5b00-7123-8456-789abcdef012');\n-- 结果：2025-09-18 14:30:00+00\n\n-- 用作默认主键\nCREATE TABLE events (\n    id UUID PRIMARY KEY DEFAULT uuidv7(),\n    event_type TEXT NOT NULL,\n    payload JSONB,\n    created_at TIMESTAMPTZ DEFAULT now()\n);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>性能对比\u003C\u002Fh3>\n\u003Cp>在包含 1 亿行的表上：\u003C\u002Fp>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>指标\u003C\u002Fth>\u003Cth>UUIDv4 PK\u003C\u002Fth>\u003Cth>UUIDv7 PK\u003C\u002Fth>\u003Cth>BIGSERIAL PK\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>插入速率（行\u002F秒）\u003C\u002Ftd>\u003Ctd>45,000\u003C\u002Ftd>\u003Ctd>112,000\u003C\u002Ftd>\u003Ctd>125,000\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>索引大小\u003C\u002Ftd>\u003Ctd>4.2 GB\u003C\u002Ftd>\u003Ctd>4.2 GB\u003C\u002Ftd>\u003Ctd>2.1 GB\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>索引缓存命中率\u003C\u002Ftd>\u003Ctd>67%\u003C\u002Ftd>\u003Ctd>94%\u003C\u002Ftd>\u003Ctd>96%\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>点查找延迟（p99）\u003C\u002Ftd>\u003Ctd>2.1 ms\u003C\u002Ftd>\u003Ctd>0.4 ms\u003C\u002Ftd>\u003Ctd>0.3 ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>UUIDv7 实现了接近 BIGSERIAL 级别的插入性能，同时保持全局唯一性。对于分布式系统、微服务以及任何需要在应用层生成 ID 而无需数据库协调的架构，uuidv7 现在是明确的默认选择。\u003C\u002Fp>\n\u003Ch2 id=\"\">虚拟生成列\u003C\u002Fh2>\n\u003Cp>PostgreSQL 从版本 12 开始支持存储生成列。PostgreSQL 18 添加了虚拟生成列——在读取时计算，不存储在磁盘上。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">CREATE TABLE products (\n    id UUID PRIMARY KEY DEFAULT uuidv7(),\n    name TEXT NOT NULL,\n    price_cents INTEGER NOT NULL,\n    tax_rate NUMERIC(5,4) NOT NULL DEFAULT 0.11,\n    -- 虚拟：读取时计算，零存储成本\n    price_with_tax NUMERIC GENERATED ALWAYS AS (price_cents * (1 + tax_rate)) VIRTUAL,\n    -- 存储：写入时计算，占用磁盘空间\n    search_vector TSVECTOR GENERATED ALWAYS AS (to_tsvector('english', name)) STORED\n);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>何时使用 VIRTUAL 与 STORED\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>使用 VIRTUAL 当：\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>计算成本低（算术、字符串连接、类型转换）\u003C\u002Fli>\n\u003Cli>您想要零存储开销\u003C\u002Fli>\n\u003Cli>该列很少被查询或仅与行一起查询\u003C\u002Fli>\n\u003Cli>您希望值始终反映当前数据\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Cstrong>使用 STORED 当：\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>计算成本高（全文搜索向量、复杂 JSON 提取）\u003C\u002Fli>\n\u003Cli>您需要对生成列建立索引\u003C\u002Fli>\n\u003Cli>该列经常在 WHERE 或 JOIN 中使用\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>虚拟列不能直接建立索引，因为磁盘上没有可索引的内容。如果您需要频繁按计算值过滤或排序，请使用 STORED。\u003C\u002Fp>\n\u003Ch2 id=\"oauth\">OAuth 身份验证支持\u003C\u002Fh2>\n\u003Cp>PostgreSQL 18 在 pg_hba.conf 中添加了 OAuth 2.0 \u002F OpenID Connect 作为原生身份验证方法。这允许用户通过 Okta、Auth0、Azure AD 或 Keycloak 等身份提供商进行身份验证。\u003C\u002Fp>\n\u003Cpre>\u003Ccode># pg_hba.conf\nhost    all    all    0.0.0.0\u002F0    oauth issuer=\"https:\u002F\u002Fauth.company.com\" client_id=\"pg-prod\"\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"\">时态约束\u003C\u002Fh2>\n\u003Cp>PostgreSQL 18 为带有期间列的表引入了时态 PRIMARY KEY、UNIQUE 和 FOREIGN KEY 约束。这将 SQL:2011 时态功能引入 PostgreSQL。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">CREATE TABLE employee_departments (\n    employee_id INTEGER NOT NULL,\n    department_id INTEGER NOT NULL,\n    valid_from DATE NOT NULL,\n    valid_to DATE NOT NULL,\n    PERIOD FOR valid_period (valid_from, valid_to),\n    PRIMARY KEY (employee_id, valid_period WITHOUT OVERLAPS)\n);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>时态约束防止同一实体的重叠期间——这是管理时间范围数据（订阅、定价层级、角色分配、库存预留）的应用程序中常见的错误来源。\u003C\u002Fp>\n\u003Ch2 id=\"returning-old-new\">RETURNING 子句中的 OLD\u002FNEW\u003C\u002Fh2>\n\u003Cp>PostgreSQL 18 允许在 UPDATE 和 DELETE 语句的 RETURNING 子句中引用 OLD 和 NEW 表值。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">UPDATE products\nSET price_cents = price_cents * 1.1\nWHERE category = 'electronics'\nRETURNING\n    id,\n    OLD.price_cents AS previous_price,\n    NEW.price_cents AS updated_price,\n    name;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"b-tree-skip-scan\">多列 B-tree 索引的 Skip-Scan\u003C\u002Fh2>\n\u003Cp>PostgreSQL 18 为多列 B-tree 索引引入了 skip-scan 优化。这允许规划器在查询的 WHERE 子句中没有前导列时也能高效使用复合索引。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">CREATE INDEX idx_locations ON locations (country, city, population);\n\n-- PG 17：全索引扫描\n-- PG 18：Skip-scan（在不同 'country' 值之间跳转）\nSELECT * FROM locations WHERE city = 'Jakarta';\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"postgresql-17-18\">迁移指南：PostgreSQL 17 到 18\u003C\u002Fh2>\n\u003Ch3>升级前检查清单\u003C\u002Fh3>\n\u003Col>\n\u003Cli>\u003Cstrong>检查扩展兼容性。\u003C\u002Fstrong> 在 PG 18 测试实例上运行 \u003Ccode>SELECT * FROM pg_available_extensions;\u003C\u002Fcode>。\u003C\u002Fli>\n\u003Cli>\u003Cstrong>审查 pg_hba.conf。\u003C\u002Fstrong> 新的 OAuth 方法是累加的——现有认证配置继续正常工作。\u003C\u002Fli>\n\u003Cli>\u003Cstrong>测试 I\u002FO 性能。\u003C\u002Fstrong> 新的异步 I\u002FO 子系统默认启用。\u003C\u002Fli>\n\u003Cli>\u003Cstrong>审计生成列。\u003C\u002Fstrong> 如果计划将存储生成列转换为虚拟列，请验证没有索引依赖于它们。\u003C\u002Fli>\n\u003Cli>\u003Cstrong>测试应用程序查询。\u003C\u002Fstrong> skip-scan 优化器更改可能会改变查询计划。\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch3>升级方法\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>pg_upgrade（大多数情况下推荐）：\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">pg_ctl -D \u002Fvar\u002Flib\u002Fpostgresql\u002F17\u002Fdata stop\npg_upgrade \\\n  --old-datadir=\u002Fvar\u002Flib\u002Fpostgresql\u002F17\u002Fdata \\\n  --new-datadir=\u002Fvar\u002Flib\u002Fpostgresql\u002F18\u002Fdata \\\n  --old-bindir=\u002Fusr\u002Flib\u002Fpostgresql\u002F17\u002Fbin \\\n  --new-bindir=\u002Fusr\u002Flib\u002Fpostgresql\u002F18\u002Fbin \\\n  --link\npg_ctl -D \u002Fvar\u002Flib\u002Fpostgresql\u002F18\u002Fdata start\nvacuumdb --all --analyze-in-stages\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>逻辑复制（零停机）：\u003C\u002Fstrong> 设置从 PG 17 到 PG 18 的逻辑复制，等待同步完成，然后切换应用程序连接字符串。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>托管服务：\u003C\u002Fstrong> AWS RDS、Google Cloud SQL、Azure Database 和 Neon 都支持最少停机时间的主版本升级。\u003C\u002Fp>\n\u003Ch2 id=\"\">常见问题\u003C\u002Fh2>\n\u003Ch3 id=\"postgresql-18\">PostgreSQL 18 是否已可用于生产？\u003C\u002Fh3>\n\u003Cp>是的。PostgreSQL 遵循严格的发布流程。.0 版本具有生产质量。等待 .1 补丁版本（通常在 .0 之后 2-3 个月）对于风险规避型组织来说是合理的策略。\u003C\u002Fp>\n\u003Ch3 id=\"uuidv4-uuidv7\">应该将现有表从 UUIDv4 切换到 UUIDv7 吗？\u003C\u002Fh3>\n\u003Cp>对于新表，使用 uuidv7() 作为默认值。对于已有 UUIDv4 主键的现有表，迁移成本很少能证明收益是合理的，除非您遇到了可衡量的索引膨胀或缓存未命中问题。\u003C\u002Fp>\n\u003Ch3 id=\"i-o\">新 I\u002FO 引擎是否需要内核更改？\u003C\u002Fh3>\n\u003Cp>io_uring 支持需要 Linux 内核 5.10 或更高版本。如果您的内核较旧，PostgreSQL 18 回退到基于工作线程的异步 I\u002FO。\u003C\u002Fp>\n\u003Ch3 id=\"pgvector\">虚拟列可以与 pgvector 一起使用吗？\u003C\u002Fh3>\n\u003Cp>不能直接使用。pgvector 嵌入通常是存储的而非计算的。但您可以使用虚拟列来计算派生指标，如 \u003Ccode>vector_dims(embedding)\u003C\u002Fcode> 或 \u003Ccode>l2_distance(embedding, reference_vector)\u003C\u002Fcode>。\u003C\u002Fp>\n\u003Ch3 id=\"\">时态约束如何与分区交互？\u003C\u002Fh3>\n\u003Cp>时态约束与声明式分区兼容。您可以按期间列的范围对表进行分区并应用时态 PRIMARY KEY 约束。\u003C\u002Fp>\n\u003Ch3 id=\"merge\">MERGE 的改进情况如何？\u003C\u002Fh3>\n\u003Cp>PostgreSQL 18 为 MERGE 语句扩展了 RETURNING 子句支持，完善了 PG 15 引入的功能集。\u003C\u002Fp>\n","zh","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:45.962076Z","PostgreSQL 18 深度解析 — uuidv7、虚拟列、异步 I\u002FO 引擎（2025）","PostgreSQL 18 功能完全指南：异步 I\u002FO 引擎（读取快 3 倍）、原生 uuidv7()、虚拟生成列、OAuth 认证、时态约束和 skip-scan 索引。","postgresql 18 功能",null,"index, follow",[22,27],{"id":23,"name":24,"slug":25,"created_at":26},"c0000000-0000-0000-0000-000000000012","DevOps","devops","2026-03-28T10:44:21.513630Z",{"id":28,"name":29,"slug":30,"created_at":26},"c0000000-0000-0000-0000-000000000005","PostgreSQL","postgresql","Engineering",[33,40,46],{"id":34,"title":35,"slug":36,"excerpt":37,"locale":12,"category_name":38,"published_at":39},"d0000000-0000-0000-0000-000000000668","为什么Bali在2026年正在成为东南亚的影响力科技中心","weishenme-bali-2026-zhengzai-chengwei-dongnanya-yingxiangli-keji-zhongxin","Bali在东南亚创业生态系统中排名第16位。随着Web3构建者、AI可持续发展初创公司和生态旅游科技公司的集中，该岛正在打造区域影响力科技之都的独特定位。","工程","2026-03-28T10:44:48.898750Z",{"id":41,"title":42,"slug":43,"excerpt":44,"locale":12,"category_name":38,"published_at":45},"d0000000-0000-0000-0000-000000000667","ASEAN数据保护拼图：开发者合规清单","asean-shuju-baohu-pintu-kaifazhe-heguiqingdan","七个ASEAN国家现已拥有全面的数据保护法律，各自具有不同的同意模型、本地化要求和处罚结构。这是一份为构建多国应用程序的开发者准备的实用合规清单。","2026-03-28T10:44:48.893467Z",{"id":47,"title":48,"slug":49,"excerpt":50,"locale":12,"category_name":38,"published_at":51},"d0000000-0000-0000-0000-000000000666","Indonesia 290亿美元数字化转型：软件公司的机遇","indonesia-290yi-meiyuan-shuzihua-zhuanxing-ruanjian-gongsi-jiyu","Indonesia IT服务市场预计在2026年达到290.3亿美元，高于2025年的243.7亿美元。云基础设施、AI、电子商务和数据中心正在推动东南亚最快的增长。","2026-03-28T10:44:48.875457Z",{"id":13,"name":53,"slug":54,"bio":55,"photo_url":19,"linkedin":19,"role":56,"created_at":57,"updated_at":57},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]