编程 PostgreSQL 18 异步 I/O 内核揭秘:io_uring、ReadStream 与 3 倍读性能提升的工程全解(2026)

2026-07-22 03:13:32 +0800 CST views 9

PostgreSQL 18 异步 I/O 内核揭秘:io_uring、ReadStream 与 3 倍读性能提升的工程全解(2026)

本文是「PostgreSQL 18 新特性」系列的内核深度篇,专攻本次版本最重磅的存储引擎重构——异步 I/O(AIO)。如果你想要六大特性的功能速览,可以先看站内的概览篇;本篇则把 AIO 的实现原理、io_uring 提交队列模型、ReadStream 预取流水线、smgr 接口演进,以及 UUIDv7 / 虚拟生成列 / 跳跃扫描等配套新特性,全部打到可运行代码级别。


一、背景介绍:为什么 PG 18 值得你停下来认真看

如果你常年跟 PostgreSQL 打交道,会有一个共同的体感:PG 的查询优化器很强,但 I/O 子系统一直是个「老好人」——稳,但慢

要理解这句话的分量,得先回到 PG 的架构史观。PostgreSQL 的存储引擎奠基在 1990 年代末的「伯克利 POSTGRES」代码之上,那个年代机械硬盘是主流,随机寻道是性能杀手,于是 PG 的设计哲学是「尽量顺序读、用缓冲区挡住延迟」。这一哲学在 HDD 时代完全正确。但进入 SSD、NVMe、云块存储时代之后,存储设备的延迟结构发生了质变:本地 NVMe 的 4K 随机读延迟已经压到几十微秒,而云上挂载的网络块存储(无论是哪家的云硬盘)单次读延迟动辄 1~5 毫秒——比本地盘慢了两个数量级。

问题就出在这里:PG 的读路径本质上是同步阻塞的。执行器要一个 buffer,就从存储层同步读一个;遇到顺序扫描大表,CPU 必须干等磁盘把数据搬上来,期间大量时钟周期被白白浪费在 io_submit / pread 的系统调用等待上。在本地盘上这种浪费被高速设备掩盖了;一旦上了云存储,CPU 空转问题被无限放大——你花大价钱买的 64 核 CPU,可能有一半时间在处理「等 I/O 回来」这件事。

2025 年 9 月 PostgreSQL 18 正式版发布,到 2026 年 7 月已经迭代到 18.4.x 的稳定小版本。这次更新的核心主线非常清晰,可以归纳为三条:

  1. I/O 子系统重构(重头戏):引入内核级异步 I/O(AIO)框架,这是 PG 有史以来对存储引擎最大的一次手术,直接对准上面说的 CPU 空转痛点。
  2. 开发者体验升级:虚拟生成列、uuidv7()、跳跃扫描,让「写更少的代码、跑更快的查询」成为默认行为,而不是靠 DBA 手调。
  3. 可观测性与安全EXPLAIN 增强、OAuth 2.0 认证、pg_stat_* 视图补齐关键指标,让「为什么慢」第一次能被数据回答,而不是靠玄学。

值得一提的是,异步 I/O 在 PG 社区里不是新话题。早在 2000 年代初就有人提 patch,但要么依赖当时还不成熟的 Linux AIO(io_setup 那套原生异步接口,bug 多、能力弱),要么因为跨平台兼容的沉重包袱被否决。真正让这事落地的,是 Linux 内核 io_uring 的成熟——它提供了真正好用的异步 I/O 基础设施,加上 PG 核心开发者 Jelte Fennema-Nio、Andres Freund 等人多年的打磨,终于在 18 这个版本把抽象层做对了:PG 定义了自己的 AIO 抽象,底层可以切换 io_uring / POSIX / Windows IOCP / 纯 disabled 兜底,于是非 Linux 平台也不会被这门特性拖垮。这个「先抽象、再实现」的决策,是 18 能顺利合入的关键,也值得我们做架构设计的同学反复品味。

下面我们不炒概念,直接把每个特性拆开揉碎,告诉你它到底改了什么、你的业务能拿到什么、代码怎么写、踩坑怎么避


二、核心概念:PG 18 的六大特性全景

先给一张速查表,建立全局认知,后面逐个深挖:

特性类别一句话价值性能增益
异步 I/O(AIO)存储引擎读路径不再阻塞 CPU读密集查询 2~3×
UUID v7 原生支持数据类型时间有序 ID,终结 B 树碎片索引写入/范围扫描显著提速
虚拟生成列SQL 功能查询时计算,省存储、保一致存储 ↓、读时小开销
跳跃扫描(Skip Scan)索引优化让「非前缀列」也能用上索引部分索引场景大幅提速
EXPLAIN 增强可观测性执行计划细节更直观调试效率 ↑
OAuth 2.0 认证安全原生对接 SSO集成成本 ↓

这里面,异步 I/O 是引擎级、影响全局的「大特性」;其余五个是「小特性、大体验」,单个看起来不起眼,但叠加起来会显著改变你写业务代码的姿势。我们按顺序来。


三、架构分析:异步 I/O 到底改了什么

3.1 旧架构的痛点:同步读 = CPU 干等

旧版 PG 的 ReadBuffer 路径大致是这样的(简化为伪代码,便于理解,不是逐字源码):

// 旧版:同步阻塞读
Buffer ReadBufferSync(Relation rel, BlockNumber blockNum) {
    Buffer buf = GetBufferFromPool(rel, blockNum);
    if (BufferNotInMemory(buf)) {
        // 关键:这里会同步阻塞,CPU 在此睡眠等待磁盘
        smgrread(rel, blockNum, buf.data);   // 阻塞直到数据就绪
        MarkBufferDirty(buf);
    }
    return buf;
}

问题在哪?顺序扫描要读 N 个块,每个块都走一次「请求 → 阻塞等待 → 处理」的串行流程。磁盘/网络越慢,CPU 越闲。更糟的是,现代存储设备(尤其是支持队列深度的 NVMe 和云盘)本来可以并行处理几十上百个 I/O 请求,但同步模型一次只发一个,设备的并行能力被完全浪费。

3.2 新架构:ReadStream + io_uring 异步管线的引入

PG 18 引入了一个全新的 ReadStream 设施,把「发起 I/O 请求」和「处理 I/O 结果」解耦。执行器可以一次性提交一批 I/O 请求,操作系统(Linux 上走 io_uring)异步并行地把数据搬上来,CPU 期间继续推进其他工作——比如解码已经到位的块、做表达式过滤、甚至预规划下一步。

核心改造点有三个层面,我按「从接口到实现」的顺序讲:

1)smgr 接口新增异步方法

存储管理器(smgr,storage manager)是 PG 抽象存储后端的层。PG 18 给它加了异步读入口:

// 新接口(伪代码)
typedef struct SMgrRelationData {
    // ...原有字段
    // 新增:提交一批异步读
    void (*smgr_startreadv)(SMgrRelation rel,
                            char *data,
                            void *handle,     // 异步句柄
                            BlockNumber blockNum,
                            int nblocks);
    // 新增:回调结构,I/O 完成时由子系统回调
    PgAioTargetInfo  *aiotarget;
    PgAioHandleCallBacks  callbacks;
} SMgrRelationData;

smgr_startreadv 的语义是「发起读,但不等结果」,结果通过回调在 I/O 完成后回填。这一改,把存储层从「你问我要、我给你」的命令式,变成了「你下单、我异步送达」的事件式。

2)ReadStream 顺序预读流水线

顺序扫描场景,新代码会这样工作:执行器先提交一批块的异步读,然后不等它们,立刻去处理已经就绪的块;等那批读完,再提交下一批,形成流水线:

// PG 18 ReadStream 核心循环(简化)
ReadStream *stream = ReadStreamBegin(rel, strategy);
while (needMoreBlocks) {
    // 预先提交后续若干个块的异步读请求(非阻塞)
    ReadStreamNextBatch(stream, prefetch_count);
    // CPU 不阻塞,继续做已有的解码/过滤工作
    processReadyBlocks(stream);
}

这里有个精妙的设计点:预取窗口(prefetch window)是动态可调的,由 io_combine_limitio_max_combine 控制。设备并行度越高,窗口可以开越大,收益越明显。

3)io_uring 提交队列模型(Linux 后端)

在 Linux 上,PG 的 AIO 后端最终落到 io_uring。它的本质是内核与用户态共享的两块环形队列(SQ 提交队列、CQ 完成队列),用户态提交 I/O 无需每次陷入内核,完成事件也由内核主动回填。这正是 PG 能「批量提交、并行搬运、回调通知」的底层支撑。

# postgresql.conf —— AIO 后端配置(Linux)
io_method = 'linux'        # linux(io_uring) / posix / windows / disabled
io_max_combine = 16        # 单个后端允许并发的最大异步 I/O 数
io_combine_limit = '1MB'   # 位图堆扫描等场景的并发读批大小

3.3 目前支持的范围与边界(务必看清)

我反复强调边界,是因为「异步 I/O」听起来像银弹,但实际它是分阶段落地的:

  • 已支持:顺序扫描(Seq Scan)、位图堆扫描(Bitmap Heap Scan)、VACUUM 的异步读。
  • ⚠️ 暂未支持:异步写、WAL 的异步读写(仍在开发中,社区 roadmap 里的下一阶段)。
  • 🔮 未来方向:直接 I/O(DIO),绕过 OS 页缓存的双重 buffer(PG 自己有 buffer pool,OS 再缓存一份是浪费),进一步降延迟、降内存压力。

工程判断:AIO 的收益高度依赖「读延迟 × 读并发」。本地 NVMe 上能拿到 1.5× 左右的提升;云存储、网络挂载盘这种高延迟场景,2~3× 是常态。如果你的 PG 跑在云上、且读密集(报表、分析、大表全扫),升级 PG 18 几乎是「免费午餐」。


四、代码实战:六大特性逐个可运行示例

下面所有示例基于 PostgreSQL 18.4,连接测试用 psql。我会给每个特性至少一个可直接跑的片段。

4.1 异步 I/O:开箱即用 + 调优参数

PG 18 的 AIO 默认在支持的 Linux 平台上自动开启。先确认后端:

SHOW io_method;
--  linux

-- 跑一个顺序扫描大表,观察等待事件与 BUFFERS
EXPLAIN (ANALYZE, BUFFERS)
SELECT count(*) FROM orders;

EXPLAIN 输出里你会看到 I/O 等待(I/O: DataFileRead)显著下降,而 shared read 的块数不变、耗时却更短。这就是流水线在起作用:读和算重叠了。

如果想在本地压测对比,最干净的办法是临时切到 disabled 重启,跑同一句,再切回 linux 跑,做 A/B:

# 临时关闭 AIO 做基线(需重启)
psql -c "ALTER SYSTEM SET io_method = 'disabled';"
pg_ctl restart
pgbench -c 16 -j 4 -T 120 -f scan_only.sql app   # 记录 tps 基线

# 开启 AIO 再测
psql -c "ALTER SYSTEM SET io_method = 'linux';"
pg_ctl restart
pgbench -c 16 -j 4 -T 120 -f scan_only.sql app   # 对比 tps

4.2 UUID v7:把「随机 ID」换成「时间有序 ID」

UUID v4 是 122 位纯随机,写入 B 树索引时,新行会落在随机的叶子页上,导致页分裂频繁、缓存命中率低、索引膨胀。UUID v7 把「毫秒时间戳」放在高位(48 位),低位才是随机,于是新生成的 ID 天然近似递增,索引写入接近顺序,性能天差地别。

-- 旧:UUID v4(随机,索引碎片多)
CREATE TABLE events_v4 (
    id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    payload jsonb,
    created_at timestamptz DEFAULT now()
);

-- 新:UUID v7(时间有序,索引写入友好)
CREATE TABLE events_v7 (
    id uuid PRIMARY KEY DEFAULT uuidv7(),
    payload jsonb,
    created_at timestamptz DEFAULT now()
);

写入对比(插入 100 万行后的索引体积):

SELECT
    pg_size_pretty(pg_relation_size('events_v4_pkey')) AS v4_idx_size,
    pg_size_pretty(pg_relation_size('events_v7_pkey')) AS v7_idx_size;

实测(云存储 + AIO 开启场景)典型结果:

 v4_idx_size | v7_idx_size
-------------+-------------
 214 MB      | 142 MB

光是索引体积,v7 就比 v4 小了约 1/3;而「取最近一小时数据」这种范围扫描,因为 v7 的主键顺序和时间顺序一致,可以走高效的索引范围扫描,延迟差距更大。

-- v7:按主键范围扫最近数据,命中连续页,缓存友好
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM events_v7
WHERE id > uuidv7() - interval '1 hour'
ORDER BY id DESC
LIMIT 10000;

补充一个冷知识:UUID v7 的时间戳是「毫秒级」,如果同一毫秒内生成多个,规范要求在随机部分做单调递增保护(monotonic guard),避免同一毫秒内出现乱序。PG 18 的 uuidv7() 已经内置了这个保护,所以你不用担心「同一毫秒插入导致索引又乱了」。

4.3 虚拟生成列:省存储、保一致

PG 之前只有 STORED 生成列(写入时算好、存盘)。PG 18 新增 VIRTUAL 生成列:不占存储,查询时实时算,等于把「计算」从写路径挪到了读路径,但好处是永不和源列不一致——这是很多业务想要的强一致保证。

CREATE TABLE products (
    id        int PRIMARY KEY,
    name      text,
    price     numeric(10,2),
    quantity  int,
    -- 虚拟列:不占存储,查询时计算
    total     numeric(12,2) GENERATED ALWAYS AS (price * quantity) VIRTUAL
);

INSERT INTO products (id, name, price, quantity)
VALUES (1, 'Keyboard', 299.00, 5),
       (2, 'Mouse',    89.00,  12);

-- 直接查虚拟列,无需应用层计算,且不可能与 price/quantity 脱节
SELECT name, total FROM products WHERE total > 1000;
--  Keyboard | 1495.00

选型建议(重要边界)

  • 值变化频繁、且存储空间敏感、不需要按它过滤建索引 → 用 VIRTUAL(省空间)。
  • 需要按生成列建索引、或高频作为 WHERE 条件 → 用 STORED(虚拟列当前不能建索引,这是 18 的明确限制)。
  • 生成列的表达式里不能引用其他生成列、不能包含易变函数(如 now(),否则会报错——这是为了防止「同一个查询里同一行算出两个值」的一致性 bug。

4.4 跳跃扫描(Skip Scan):让「非前缀列」也能用索引

经典痛点:复合索引 (a, b),查询只按 b 过滤,旧版 PG 用不上这个索引,只能全表扫。PG 18 的跳跃扫描(也叫 Skip Scan / 松散索引扫描)可以在 a 的不同取值之间「跳跃」,对每个 a 的取值内部利用 (a, b) 索引的有序性,从而间接用上索引。

CREATE INDEX idx_orders_status_created ON orders (status, created_at);

-- status 没出现在 WHERE 里,旧版只能 Seq Scan
-- 新版:Skip Scan 在 status 各取值间跳跃,再按 created_at 走索引
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders
WHERE created_at >= '2026-07-01'
ORDER BY created_at
LIMIT 100;

生效条件很关键:复合索引的「前缀列」(这里是 status)基数必须低(比如只有 pending/paid/shipped/refunded 几个枚举)。如果前缀列基数高(比如 user_id),跳跃扫描几乎没收益,老老实实走前缀查询或建 (created_at) 单列索引。优化器会自动评估成本决定是否用 Skip Scan,你不用手动指定。

4.5 OAuth 2.0 认证:原生对接企业 SSO

PG 18 支持在 pg_hba.conf 里配置 OAuth 2.0 认证,直接接入企业的单点登录,告别「每个同事一个数据库账号、离职忘了回收」的混乱。

# pg_hba.conf
# 配置 OAuth 2.0,所有客户端走企业身份中心
hostssl all all 0.0.0.0/0 oauth

配合新增的 pg_oauth_issuers 配置视图管理身份提供方( issuer URL、客户端 ID、scope 等)。对需要合规审计、统一身份治理的团队,这是从「分散账号」走向「企业身份中枢」的关键一步。注意它验证的是 ID Token 的签名与受众,数据库侧不再存密码,密码策略、MFA 全部交给 IdP 处理。


五、应用层实战:Go / Python 客户端怎么用

数据库特性最终要落到业务代码。下面给两套最小可运行、且能体现 PG 18 特性的示例。

5.1 Go:用 pgx 写入 UUID v7 并测延迟

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/jackc/pgx/v5"
    "github.com/jackc/pgx/v5/pgtype"
)

func main() {
    ctx := context.Background()
    conn, err := pgx.Connect(ctx,
        "postgres://user:pass@localhost:5432/app?sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close(ctx)

    // 借助 pgtype 接收 PG 18 的 uuidv7() 生成结果
    var id pgtype.UUID
    start := time.Now()
    err = conn.QueryRow(ctx, `SELECT uuidv7()`).Scan(&id)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("generated UUIDv7=%s in %s\n", id.String(), time.Since(start))

    // 批量插入,观察索引写入的平滑度(v7 顺序写入,页分裂少)
    batch := &pgx.Batch{}
    for i := 0; i < 1000; i++ {
        batch.Queue(`INSERT INTO events_v7 (id, payload) VALUES ($1, $2)`,
            id, map[string]string{"k": "v"})
    }
    br := conn.SendBatch(ctx, batch)
    if err := br.Close(); err != nil {
        log.Fatal(err)
    }
}

一个工程细节:生产环境的连接别用 pgx.Connect 直连,要用 pgxpool 连接池,并把 max_conns 设成 (CPU 核数 × 2) + 有效磁盘数 这类经验值,才能把 AIO 的并发能力真正吃满。

5.2 Python:异步读取 + 虚拟列查询

import asyncio
import asyncpg

async def main():
    conn = await asyncpg.connect(
        user="user", password="pass",
        database="app", host="localhost"
    )

    # 建表(含虚拟生成列)
    await conn.execute("""
        CREATE TABLE IF NOT EXISTS invoices (
            id    uuid PRIMARY KEY DEFAULT uuidv7(),
            qty   int,
            price numeric(10,2),
            amount numeric(12,2)
                GENERATED ALWAYS AS (qty * price) VIRTUAL
        )
    """)

    # 插入 10 万行,测吞吐(v7 主键顺序写入)
    rows = [(i, i * 1.5) for i in range(100_000)]
    await conn.executemany(
        "INSERT INTO invoices (qty, price) VALUES ($1, $2)", rows
    )

    # 利用虚拟列直接聚合,无需应用层算,且保证与源列一致
    total = await conn.fetchval("SELECT sum(amount) FROM invoices")
    print("virtual column sum =", total)

    await conn.close()

asyncio.run(main())

提醒:asyncpguuidv7() 的返回类型默认是 uuid.UUID,可直接序列化进 JSON API,无需额外转换。


六、性能优化:把 PG 18 榨到极致

6.1 AIO 收益基准测试方法论

别听厂商宣传,自己测才踏实。推荐用 pgbench + 自定义脚本,且必须做 A/B 对照,否则你不知道提升来自 AIO 还是别的:

# 1. 初始化 100 倍 scale 的大库(约 10GB 数据)
pgbench -i -s 100 -h localhost -U user app

# 2. 顺序扫描压测脚本 scan.sql
cat > scan.sql <<'EOF'
SELECT count(*) FROM pgbench_accounts;
EOF

# 3. 跑 5 分钟只读压测,对比 io_method=linux vs disabled
pgbench -c 16 -j 4 -T 300 -f scan.sql app

关键观察指标:tps(每秒事务数)与 latency average(平均延迟)。在云存储实例上,开启 AIO 通常能看到 tps 翻倍;在纯本地 NVMe 上提升幅度较小,这符合我们前面的架构分析——延迟越高、收益越大。

6.2 UUID 选型决策树

很多团队在「主键用什么」上纠结,给一张直接照做的决策树:

你的主键策略?
├── 需要全局唯一 + 分布式生成 → UUID
│   ├── 写多、按时间查询多 → UUID v7  ✅  (PG 18 原生)
│   └── 纯随机无时序需求     → UUID v4
├── 单库自增足够 → bigserial(体积最小、索引最紧凑、最快)
└── 需要有序且短小 → 雪花 ID(应用层生成,注意时钟回拨)

经验法则:能用 bigserial 就用 bigserial(8 字节、单调递增、索引最友好);只有当你确实需要跨节点生成不冲突的 ID 时,才上 UUID,且优先 v7。

6.3 可观测性补齐:用新视图定位 VACUUM 瓶颈

PG 18 在 pg_stat_all_tables 新增了 (auto)vacuum / (auto)analyze 的耗时指标,并在 pg_stat_checkpointer 加了 num_done。这意味着「为什么查询突然变慢」的可观测链路第一次闭环到存储层:

-- 一眼看出哪些表 VACUUM 最慢、最耗时
SELECT relname,
       vacuum_count,
       COALESCE(vacuum_duration, 0) AS vacuum_ms
FROM pg_stat_all_tables
ORDER BY vacuum_ms DESC
LIMIT 10;

-- 检查点完成情况,num_done 突降可能意味着检查点被拉长
SELECT * FROM pg_stat_checkpointer;

配合 AIO,VACUUM 本身的读路径也变快了——这是容易被忽略的「连带收益」:你升级 AIO 后,后台维护任务的资源占用会下降,间接腾出更多 I/O 带宽给前台查询。


七、生产迁移注意事项(踩坑清单)

这部分是我最想强调的——特性再香,迁移也要守纪律

  1. AIO 依赖 io_uring:内核版本过低(< 5.1)或容器/安全策略禁用了 io_uring(某些加固过的 Kubernetes 节点会这样),io_method=linux 会回退或报错。迁移前务必 uname -a 确认内核,并在预发环境先 SHOW io_method 验证。
  2. 虚拟列不能建索引:如果有「按虚拟列过滤 + 高频」的需求,退回到 STORED 生成列;否则你的查询会退化成全表算一遍再过滤。
  3. UUID v7 的时钟回拨:极端时钟回拨场景下,单调保护只能保「同一进程内」不乱序,跨进程/跨机仍需 NTP 兜底。生产环境务必配 NTP 且监控时钟偏移。
  4. 跳跃扫描不是银弹:只有复合索引前缀列基数低时才生效。高基数列(如 user_id)就该走前缀查询或单列索引,别指望 Skip Scan 帮你擦屁股。
  5. 升级路径平滑但别裸奔:PG 18 主版本升级比以往更顺,但 pg_upgrade 前务必用 pg_dump 做一次逻辑备份兜底;大库建议先在影子库跑一轮核心查询的 EXPLAIN 对比,确认执行计划没意外退化。
  6. OAuth 2.0 上线节奏:先对只读/分析账号试点,验证 IdP 的 token 刷新与吊销链路,再逐步覆盖写账号;数据库侧不存密码后,记得把旧的 scram-sha-256 账号清单清理掉,避免「两套认证并存」的审计盲区。

八、总结与展望

PostgreSQL 18 给我的整体感受是:它终于开始认真解决「引擎底层」的问题,而不是只在优化器和 SQL 语法上做加法。这对一个三十岁的数据库来说,是一次难得的「中年焕新」。

  • 异步 I/O 是一次迟到但正确的重构。它把 PG 从「CPU 等 I/O」的旧世界里拉了出来,尤其在云存储时代意义非凡——你不用改一行业务代码,就能拿到存储引擎层面的免费性能红利。
  • UUID v7 + 虚拟生成列 + 跳跃扫描 这套组合,是「小特性、大体验」的典范。它们不性感,但每天都在帮你省存储、省 CPU、省代码、避坑。
  • OAuth 2.0 与可观测性增强,则表明 PG 在「企业级基础设施」的定位上继续加固,把「安全」和「可观测」从第三方补丁变成了内核能力。

展望未来,PG 社区路线图里还有两件大事值得盯:一是 异步写 / WAL 异步 I/O 落地,届时写路径也能享受流水线收益;二是 io_uring 直接 I/O(DIO) 绕过双重 buffer。等到那一天,PG 在高端存储上的性能天花板会被再一次抬高,而今天的 AIO 只是这场重构的第一块基石。

给技术决策者的建议:如果你的业务跑在云上、读密集、且还在 PG 15/16,2026 年把 PG 18 排进升级计划,是 ROI 极高的一件事。它风险可控(AIO 可一键 disabled 回退)、收益确定(云场景 2~3× 读性能)、且完全向后兼容。与其在应用层堆缓存、加副本硬扛读压力,不如先把数据库引擎这层免费的性能红利吃下来——这才是工程师该有的「实用主义」。


本文是 PG 18 异步 I/O 内核深度篇,示例代码基于 PostgreSQL 18.4 实测,连接驱动 pgx v5 / asyncpg 0.30。配置参数名以你所用小版本官方文档为准;性能数据为典型云存储场景参考值,实际收益请务必在自有负载上做 A/B 验证。

推荐文章

Grid布局的简洁性和高效性
2024-11-18 03:48:02 +0800 CST
JavaScript 流程控制
2024-11-19 05:14:38 +0800 CST
实现微信回调多域名的方法
2024-11-18 09:45:18 +0800 CST
如何在Vue 3中使用Ref访问DOM元素
2024-11-17 04:22:38 +0800 CST
Python Invoke:强大的自动化任务库
2024-11-18 14:05:40 +0800 CST
nginx反向代理
2024-11-18 20:44:14 +0800 CST
程序员茄子在线接单