psql 中的流水线操作(PostgreSQL 18)

原文地址 https://postgresql.verite.pro/blog/2025/10/01/psql-pipeline.html

psql 中的流水线操作(PostgreSQL 18)

2025 年 10 月 1 日

Postgres 中的流水线是什么?

流水线是网络协议支持的一种客户端特性,其核心思想是:在发送下一条查询前,无需等待之前已发送查询的结果返回。这种方式通过两种途径提升吞吐量:

客户端、网络和服务器可以并行工作。例如,网络可能在传输第 (N-1) 条查询结果的同时,服务器正在执行第 N 条查询,而客户端正在发送第 (N+1) 条查询------所有这些操作同时进行。

网络利用率更高,因为连续的查询可以被分组到相同的网络数据包中,从而减少总体数据包数量。

流水线功能自 7.4 版本(2003 年发布)引入扩展查询协议后便成为可能。但直到 2021 年 PostgreSQL 14 发布,才可以通过客户端 C 库 libpq 使用该功能。此后,一些基于 libpq 的驱动程序(如 psycopg3)开始支持流水线。

上周发布的 PostgreSQL 18 中,命令行客户端 psql 新增了在 SQL 脚本中使用流水线操作的命令,使其变得更加易用。虽然这一新增功能并非该版本的突出特性,但它能显著提升查询吞吐量,我们将在下面的简单测试中看到这一点。

psql 命令

流水线操作以 \startpipeline 开始,在最简单的情况下,其后跟随 SQL 查询,并以 \endpipeline 结束。如果需要中间结果,可以使用 \syncpipeline 强制设置一个同步点,并使用 \getresults 获取到该点为止的所有结果。此外,启动流水线会创建一个隐式事务。如果某个查询失败,自开始(或上一个同步点)以来的所有更改都将被回滚。

如果你了解使用 \; 语法将多个查询分组到同一请求中的技术,那么它与流水线操作有相似之处:两者都用于减少服务器往返次数,并且在事务方面具有相同的语义。从某种意义上说,流水线操作是扩展查询协议中对简单查询协议中多语句查询(psql 中的 \;)的演进。

性能测试

我们做一个简单的测试,使用 INSERT ... ON CONFLICT 查询导入设备数据。对于同一设备、同一日期的情况会更新行,否则插入新行。需要注意的是,如果我们想无条件追加所有行,使用 COPY 会更合适,流水线操作则非必需,因此本次测试选择了更复杂的插入或更新操作。

以下 bash 代码根据参数决定是否使用流水线来导入(随机生成的)数据。

bash 复制代码
function import_data
{
  local count=$1  # 导入多少行?
  local pipeline=$2 # 1 或 0
  local now_ts=$(date +%s)

  (
    echo 'PREPARE s AS insert into events(device, recorded_at, measure)
values($1, to_timestamp($2), $3) on conflict(device,recorded_at) do update set measure=excluded.measure;'
    echo "BEGIN;"
    [[ $pipeline = 1 ]] && echo "\\startpipeline"
    for i in $(seq 1 $count)
    do
      device=$RANDOM
      secs=$(($now_ts + $RANDOM*50))
      measure=${RANDOM}"."${RANDOM}
      echo "execute s($device, '$secs', $measure);"
    done
    [[ $pipeline = 1 ]] && echo "\\endpipeline"
    echo "COMMIT;"
  ) | $psql -q -v ON_ERROR_STOP=1
}

让我们尝试以 100、1000、5000、10000、50000、100000 行为批次,分别使用和不使用流水线操作,并比较这些批次的处理速度。

此外,由于网络速度在此处影响很大,我们将在三种典型的网络连接下进行测试:

  • 本地主机(ping 时间约 0.04ms):客户端和服务器在同一主机上。
  • 局域网(ping 时间约 1ms):客户端和服务器仅通过一个 1GB/s 的以太网交换机连接。
  • 广域网(ping 时间约 4ms):服务器通过公共互联网连接访问。

最后,每种情况运行 5 次,我们只取运行时间的中位数。

![本地主机性能对比图]

在同一主机上,流水线带来的加速效果从最小批次的 1.5 倍到最大批次的 5 倍不等。

![局域网性能对比图]

在局域网连接上,最小批次的加速效果是 2.6 倍,而较大批次则高达 42 倍。

![广域网性能对比图]

在最慢的网络(广域网)上,效果更加显著。加速比在 5.4 倍到 71 倍之间!

结论

这些加速效果表明,在没有流水线操作的情况下,当我们发送小查询批次时,网络利用率是多么不足:网络数据包就像载客 50 人的巴士,每次却只载着一位乘客行驶。

在我们的示例中,为了在这方面进行优化,我们只需添加一对 \startpipeline\endpipeline 命令。这是因为我们的查询不依赖于同一批次中先前查询的结果(除非一个查询失败导致整个批次失败的情况)。

如果没有流水线操作,我们仍然可以通过在每条查询的 VALUES 子句中添加多行数据(而不是每查询一行)来优化测试。但找到每个查询应包含多少数据行的最佳平衡点并不容易,而且带有数千个参数的大型查询在服务器端处理起来也并非易事。此外,如果客户端逻辑更复杂(例如有条件地操作多个表),那么在流水线中运行简单语句同时使用逐行逻辑可能会容易得多。

流水线元命令是在 psql 18 版本中添加的,但它们并不要求服务器端必须是 PostgreSQL 18。对于那些对此功能感兴趣但暂时无法升级服务器的人,您仍然可以升级到最新版本的 psql:它在尽可能保持向后兼容性。

相关推荐
enfpZZ小狗2 小时前
使用Flask快速搭建轻量级Web应用
jvm·数据库·python
Geek攻城猫2 小时前
深入理解 SQL 多字段排序:从基础到高级技巧
数据库·sql
Koma_zhe2 小时前
【文本转语音工具VibeVoice】告别单调配音,VibeVoice+cpolar 让多角色音频创作随时随地搞定
linux·人工智能·ai·音视频·语音识别
b***25112 小时前
激光焊接机如何破解新能源电池制造的三大焊接难题?
人工智能·自动化·制造
洛_尘2 小时前
MySQL 7:数据库设计
数据库·mysql
AI营销先锋2 小时前
原圈科技领跑破解B2B增长焦虑
大数据·人工智能·机器学习
新加坡内哥谈技术2 小时前
Matic 的家庭故事-吸尘器能引发一场机器人革命吗?
人工智能
pusheng20252 小时前
普晟传感商用一氧化碳探测解决方案:欧洲及中东市场概述
人工智能
heze092 小时前
sqli-labs-Less-22
数据库·mysql·网络安全