PostgreSQL 新版本就一定好

PostgreSQL 新版本就一定好

PostgreSQL的版本推进的很快,目前已经到了PG18的非正式版本研发的状态。基于一些数据库产品在推进时容易出现的一些问题,比如新版本的性能在某些方面还不如老的版本这个问题。

我们将展开一个新的PostgreSQL的系列,从相近的版本去发现版本是否存在差异,来从版本的差异上去寻找一些问题。

找差异的方法有很多,我们就从最直接的方式来,我们准备了,两台同样的虚拟机,同样的配置,且虚拟机在同一台物理机上。同样去安装 POSTGRESQL 16.8 和 POSTGRESQL 17.4,用同样的方式去编译数据库,同样的参数。同样的压测的方法。我们来进行数据的采集,最终我们获得版本的差异为我们带来的不同。

一、数据的插入的性能差异。

数据的输入时的性能差异是很多数据库系统在一直优化,且努力让数据写入的速率的,这里我们通过基本pg_bench 来进行简易的测试,在同样配置的数据库中,插入1000万数据,我们来看差距是否存在。我们同样的事情至少做三遍并且我们会将数据列出来。

代码语言:javascript复制Initialization started at: 2025-06-02 06:47:53

[postgres@postgresql16 ~]$ pgbench -i -s 100 -U postgres -d my_pgbench_db

dropping old tables...

creating tables...

generating data (client-side)...

2025-06-02 06:48:00.362 CST [10778] LOG: checkpoint starting: wal.89 s)

10000000 of 10000000 tuples (100%) done (elapsed 7.08 s, remaining 0.00 s)

vacuuming...

creating primary keys...

donein 10.31 s (drop tables 0.06 s, create tables 0.06 s, client-side generate 7.32 s, vacuum 0.17 s, primary keys 2.71 s).

[postgres@postgresql16 ~]$ echo"Initialization finished at: $(date '+%Y-%m-%d %H:%M:%S')"

Initialization finished at: 2025-06-02 06:48:03

[postgres@postgresql16 ~]$ echo"end"

代码语言:javascript复制[postgres@postgresql17 ~]$ echo "Initialization started at: $(date '+%Y-%m-%d %H:%M:%S')"

Initialization started at: 2025-06-01 10:47:16

[postgres@postgresql17 ~]$ pgbench -i -s 100 -U postgres -d my_pgbench_db

dropping old tables...

creating tables...

generating data (client-side)...

vacuuming...

creating primary keys...

donein 6.86 s (drop tables 0.05 s, create tables 0.00 s, client-side generate 4.96 s, vacuum 0.16 s, primary keys 1.69 s).

[postgres@postgresql17 ~]$ echo"Initialization finished at: $(date '+%Y-%m-%d %H:%M:%S')"

Initialization finished at: 2025-06-01 10:47:23

[postgres@postgresql17 ~]$ echo"end"

测试编号

数据量 (万条)

完成时间

版本

1

1000

4.46S

16

2

1000

4.48S

16

3

1000

6.63S

16

4

1000

4.66S

17

6

1000

4.59S

17

7

1000

4.96S

17

除此以外我们还进行了普通的测试,其中包含了客户端从10到50的逐渐数据的查询和DML的操作,下面我们将给出相关的测试脚本和过程。

代码语言:javascript复制[postgres@postgresql17 ~]$ bash test.sh

测试结果将保存到: pgbench_results_20250601_120531

---------------------------------------------------------

## 正在运行客户端数量为: 10 的测试 ##

开始时间: 2025-06-01 12:05:31

---------------------------------------------------------

## pgbench 命令执行失败,客户端数量为: 10 ##

请检查错误信息,日志文件: pgbench_results_20250601_120531/pgbench_c10_t30.log

暂停 5 秒,然后继续下一个客户端数量...

## 正在运行客户端数量为: 20 的测试 ##

开始时间: 2025-06-01 12:05:36

---------------------------------------------------------

## pgbench 命令执行失败,客户端数量为: 20 ##

请检查错误信息,日志文件: pgbench_results_20250601_120531/pgbench_c20_t30.log

暂停 5 秒,然后继续下一个客户端数量...

## 正在运行客户端数量为: 30 的测试 ##

开始时间: 2025-06-01 12:05:41

---------------------------------------------------------

## pgbench 命令执行失败,客户端数量为: 30 ##

请检查错误信息,日志文件: pgbench_results_20250601_120531/pgbench_c30_t30.log

暂停 5 秒,然后继续下一个客户端数量...

## 正在运行客户端数量为: 40 的测试 ##

开始时间: 2025-06-01 12:05:46

---------------------------------------------------------

## pgbench 命令执行失败,客户端数量为: 40 ##

请检查错误信息,日志文件: pgbench_results_20250601_120531/pgbench_c40_t30.log

暂停 5 秒,然后继续下一个客户端数量...

## 正在运行客户端数量为: 50 的测试 ##

开始时间: 2025-06-01 12:05:51

---------------------------------------------------------

## pgbench 命令执行失败,客户端数量为: 50 ##

请检查错误信息,日志文件: pgbench_results_20250601_120531/pgbench_c50_t30.log

所有测试阶段完成!

所有详细结果文件位于: pgbench_results_20250601_120531

代码语言:javascript复制#!/bin/bash

# --- 配置参数 ---

DB_USER="postgres" # 数据库用户

DB_NAME="my_pgbench_db" # 数据库名

PGBENCH_SCRIPT="custom_mixed.sql"# pgbench 脚本文件

SCALE_FACTOR=100 # 数据缩放因子 (与初始化时保持一致,确保脚本变量正确)

THREADS=8 # 每个pgbench实例使用的线程数 (通常设置为CPU核心数)

DURATION=30 # 每个测试阶段的运行时间 (秒)

PROGRESS_REPORT=5 # 每隔多少秒打印一次进度报告

START_CLIENTS=10 # 起始客户端数量

END_CLIENTS=50 # 结束客户端数量

CLIENT_STEP=10 # 每次增加的客户端步长

PAUSE_SECONDS=5 # 每个测试阶段之间暂停的秒数

OUTPUT_DIR="pgbench_results_$(date +%Y%m%d_%H%M%S)"# 结果输出目录

# --- 函数:打印分隔线 ---

print_separator() {

echo"---------------------------------------------------------"

}

# --- 创建结果输出目录 ---

mkdir -p "$OUTPUT_DIR"

echo"测试结果将保存到: $OUTPUT_DIR"

print_separator

# --- 循环执行 pgbench ---

for clients in $(seq $START_CLIENTS$CLIENT_STEP$END_CLIENTS)

do

echo"## 正在运行客户端数量为: $clients 的测试 ##"

echo"开始时间: $(date '+%Y-%m-%d %H:%M:%S')"

print_separator

OUTPUT_FILE="${OUTPUT_DIR}/pgbench_c${clients}_t${DURATION}.log"

pgbench -f "$PGBENCH_SCRIPT" \

-c "$clients" \

-j "$THREADS" \

-T "$DURATION" \

-r \

-P "$PROGRESS_REPORT" \

-U "$DB_USER" \

-d "$DB_NAME" \

-s "$SCALE_FACTOR" \

> "$OUTPUT_FILE" 2>&1 # 将所有输出重定向到文件

EXIT_CODE=$?

if [ $EXIT_CODE -ne 0 ]; then

echo"## pgbench 命令执行失败,客户端数量为: $clients ##" | tee -a "$OUTPUT_FILE"

echo"请检查错误信息,日志文件: $OUTPUT_FILE"

else

echo"## 客户端数量为: $clients 的测试完成 ##"

echo"结束时间: $(date '+%Y-%m-%d %H:%M:%S')"

echo"结果已保存到: $OUTPUT_FILE"

print_separator

# 打印关键摘要到控制台

echo"摘要 (客户端: $clients):"

grep "tps =""$OUTPUT_FILE" | head -n 1

grep "latency average =""$OUTPUT_FILE"

print_separator

fi

if [ "$clients" -lt "$END_CLIENTS" ]; then

echo"暂停 ${PAUSE_SECONDS} 秒,然后继续下一个客户端数量..."

sleep "$PAUSE_SECONDS"

fi

done

echo"所有测试阶段完成!"

echo"所有详细结果文件位于: $OUTPUT_DIR"

代码语言:javascript复制-- custom_mixed.sql

`

-- 联合查询和写入的 pgbench 脚本

-- 随机选择一个账户ID,范围是 1 到 (scale_factor * 100000)

-- 假设 scale_factor = 10,则 aid 范围是 1 到 10000000

\set scale_factor 100

\set aid random(1, :scale_factor * 100000)

\set bid random(1, :scale_factor * 1)

\set tid random(1, :scale_factor * 10)

\set delta random(-5000, 5000)

-- 随机的金额变动 (注释移动到单独一行,或者删除)

BEGIN;

-- 查询操作 1: 查询特定账户的余额

SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

-- 写入操作 1: 更新账户余额

UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

-- 写入操作 2: 更新出纳员余额

UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

-- 写入操作 3: 更新分支余额

UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

-- 写入操作 4: 插入历史记录

INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, now());

-- 查询操作 2: 联合查询一些数据(例如,从账户表和出纳员表联合查询)

SELECT a.aid, a.abalance, t.tbalance

FROM pgbench_accounts a, pgbench_tellers t

WHERE a.aid = :aid AND t.tid = :tid;

COMMIT;

测试批次

客户端数量 (C)

线程数 (J)

持续时间 (秒)

事务总数

失败事务数

平均延迟 (ms)

延迟标准差 (ms)

TPS (每秒事务数)

备注

17

10

8

30S

12993

0

14.975 ms

629.864 ms

667.573826

17

20

8

30S

20589

0

38.841 ms

962.272 ms

514.764547

17

30

8

30S

10505

0

87.947 ms

1308.477 ms

341.008574

17

40

8

30S

20872

0

107.095 ms

1529.057 m

90.696109

17

50

8

30S

24726

0

66.365 ms

1278.599 ms

752.918106

16

10

8

30S

109111

0

2.636 ms

508.185 ms

3634.577691

16

20

8

30S

120542

0

4.748

1.078 ms

4013.857067

16

30

8

30S

123626

0

6.881 ms

3.400 ms

4116.228912

16

40

8

30S

125420

0

8.981 ms

8.981 ms

4175.357838

16

50

8

30S

128547

0

10.915 ms

10.915 ms

4279.730086

特殊的情况截图特殊的情况截图

从数据上看,PG17 PG16 各有自己的特点,但PG16的数据出奇的比PG17的好,我在测试的时候认为是突发情况,就对PG16的数据库又进行了4次测试,对PG17进行了同样的3次此时,最终我不得不把上面的数据呈现出来。

这也是我一直担心的一个问题,新版本的性能比老版本的性能低。出现这个问题在数据库业界并不是少数派事件,在某开源数据库的共识是新的版本的性能逐渐下降对比之前5.7的性能8.0的性能在一些简单的操作上更慢了。

所以这次我也对PG进行了测试没想到得出的结果也让我...... ,同时我也想提醒一件事,也是最近一个培训课上一些同学经常问我的问题,为什么不讲最新的版本。

我的解释是

1 培训大纲的要求

2 新版本未必比旧版本在实用性上强

3 一些同学盲目求新,新版本和旧版本的一些知识体系又了改变,则课上不会在讲之前的一些坑,因为新版本上解决了老版本的问题,这点尤其在PG上非常突出。教学的任务可能对我来说更轻松了,但如果你去的单位用的是老版本,那么你不进行体系化的对老版本的熟悉,你讲无法处理新版本已经不出现,老版本依然是问题的问题。

这也是我这篇文章想说的,数据库相对运维来说更严谨,新版本固然好,但是完全好吗,自己思索思索。

相关推荐

罗技鼠标为什么这么贵?罗技鼠标怎么样?
365网站取款不给怎么办

罗技鼠标为什么这么贵?罗技鼠标怎么样?

📅 10-23 👁️ 6509
“睁着眼睛说瞎话”“三六九等”…外交部又有“神翻译”
财政部 中央文明办 国家发展改革委 工业和信息化部 公安部 民政部 文化和旅游部 人民银行 市场监管总局 体育总局 国家网信办 银保监会公告2018年第105号
DeepSeek评足坛历史十大“金左脚”:梅西第二,苏克上榜
【PESCM/实况球会经理人】入门丨进阶贴-1
GBT36507-2018

【PESCM/实况球会经理人】入门丨进阶贴-1

📅 08-02 👁️ 6519
如何在QQ空间高效管理和删除留言,保持社交平台的整洁?
365网站取款不给怎么办

如何在QQ空间高效管理和删除留言,保持社交平台的整洁?

📅 08-06 👁️ 6920