DeepSeek总结的PostgreSQL 19新功能:第一部分

PostgreSQL 19:第一部分 或 CommitFest 2025-07

来源: habr.com

原文地址:https://postgr.es/p/7tA

我们正在启动一个关于 PostgreSQL 19 即将到来变化的新系列文章。第一篇文章聚焦于去年夏天的七月 CommitFest 中的更新内容。


📑 目录

  • 连接服务文件:支持 libpq 参数和 psql 变量
  • regdatabase:用于数据库标识符的类型
  • pg_stat_statements:通用计划与自定义计划计数器
  • pg_stat_statements:FETCH 命令规范化
  • pg_stat_statements:IN 子句中的参数列表命令规范化
  • EXPLAIN:Memoize 节点估算
  • btree_gin:整数类型的比较运算符
  • pg_upgrade:优化大对象迁移
  • 优化临时表截断
  • 规划器:Append 和 MergeAppend 节点中的增量排序
  • 域约束验证不再阻塞 DML 操作
  • CHECKPOINT 命令参数
  • COPY FROM:跳过初始行
  • pg_dsm_registry_allocations:动态共享内存使用

🔌 连接服务文件:支持 libpq 参数和 psql 变量

提交: [092f3c63efc6], [6b1c4d326b06]

当使用连接服务文件连接到服务器时,现在可以通过连接字符串中的新参数 servicefile 指定文件名。

例如,当前目录下有一个 demo.conf 文件:

bash 复制代码
$ cat ./demo.conf
[demo]
host=localhost
port=5401
user=postgres
dbname=demo
options=-c search_path=bookings

你可以使用它进行连接:

bash 复制代码
$ psql 'servicefile=./demo.conf service=demo'
psql (19devel)
Type "help" for help.

postgres@demo(19.0)=#

在 psql 中,新增了一个 SERVICEFILE 变量用于指定服务文件名:

sql 复制代码
postgres@demo(19.0)=# \echo :SERVICEFILE
./demo.conf

🏷️ regdatabase:用于数据库标识符的类型

提交: [bd09f024a]

对象标识符别名类型家族的新成员。regdatabase 类型支持数据库名称与其标识符之间的双向转换。

sql 复制代码
SELECT current_database()::regdatabase,
       current_database()::regdatabase::oid
\gx
-[ RECORD 1 ]----+------
current_database | demo
current_database | 16561

📊 pg_stat_statements:通用计划与自定义计划计数器

提交: [3357471cf]

pg_stat_statements 视图现在新增两列,用于跟踪查询执行中选择通用计划和自定义计划的次数:

sql 复制代码
SELECT pg_stat_statements_reset();

SELECT * FROM bookings WHERE book_ref = $1 \bind 'NWQI2S' \g /dev/null
SELECT * FROM bookings WHERE book_ref = $1 \bind 'WF2DGZ' \g /dev/null

SELECT query, calls, generic_plan_calls, custom_plan_calls
FROM pg_stat_statements
WHERE query ~ 'bookings'
\gx
-[ RECORD 1 ]------+-------------------------------------------
query              | SELECT * FROM bookings WHERE book_ref = $1
calls              | 2
generic_plan_calls | 0
custom_plan_calls  | 2

🔄 pg_stat_statements:FETCH 命令规范化

提交: [bee23ea4d]

在规范化 FETCH 命令时,获取行数现在被替换为常量。这意味着获取不同行数的 FETCH 命令将共享相同的查询标识符,并在 pg_stat_statements 中显示为单一条目:

sql 复制代码
SELECT pg_stat_statements_reset();

BEGIN;
DECLARE cur CURSOR FOR SELECT * FROM flights;
FETCH 1 cur\g /dev/null
FETCH 2 cur\g /dev/null
FETCH -1 cur\g /dev/null
COMMIT;

SELECT queryid, query, calls
FROM pg_stat_statements
WHERE query ~ '^FETCH'
\gx
-[ RECORD 1 ]----------------
queryid | 4164749676997500190
query   | FETCH $1 cur
calls   | 3

📝 pg_stat_statements:IN 子句中的参数列表命令规范化

提交: [c2da1a5d6]

带有 IN 子句中常量列表的命令已在版本 18 中实现了规范化。在版本 19 中,这一规范化不仅适用于常量,还适用于参数列表:

sql 复制代码
SELECT pg_stat_statements_reset();

SELECT * FROM flights WHERE flight_id IN (1,2) \g /dev/null
SELECT * FROM flights WHERE flight_id IN (1,2,3) \g /dev/null

SELECT * FROM flights WHERE flight_id IN ($1,$2) \bind 11 12 \g /dev/null
SELECT * FROM flights WHERE flight_id IN ($1,$2,$3) \bind 21 22 23 \g /dev/null
SELECT * FROM flights WHERE flight_id IN ($1,$2,$3,$4) \bind 31 32 33 34 \g /dev/null

SELECT queryid, query, calls
FROM pg_stat_statements
WHERE query ~ 'flights'
-[ RECORD 1 ]-----------------------------------------------------
queryid | -5928905334469394952
query   | SELECT * FROM flights WHERE flight_id IN ($1 /*, ... */)
calls   | 5

这对于使用扩展查询协议的应用程序特别有用。


🔍 EXPLAIN:Memoize 节点估算

提交: [4bc62b86849]

为了帮助理解规划器为何选择使用 Memoize 节点,EXPLAIN 输出现在包含该节点的规划器估算值(显示在 Estimates 行中):

sql 复制代码
EXPLAIN            
SELECT * FROM routes r
  JOIN airports_data a ON r.departure_airport = a.airport_code
WHERE r.days_of_week = '{1,2,3,4,5,6,7}';
                                               QUERY PLAN                                               
--------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.29..212.71 rows=898 width=293)
   ->  Seq Scan on routes r  (cost=0.00..111.12 rows=898 width=103)
         Filter: (days_of_week = '{1,2,3,4,5,6,7}'::integer[])
   ->  Memoize  (cost=0.29..1.08 rows=1 width=190)
         Cache Key: r.departure_airport
         Cache Mode: logical
         Estimates: capacity=73 distinct keys=73 lookups=898 hit percent=91.87%
         ->  Index Scan using airports_data_pkey on airports_data a  (cost=0.28..1.07 rows=1 width=190)
               Index Cond: (airport_code = r.departure_airport)
(9 rows)

此行显示规划器对以下指标的估算:

  • 哈希表大小
  • 哈希表中唯一元素的数量
  • 哈希表被查找的次数
  • 命中率

使用 EXPLAINanalyze 参数运行可显示估算与实际结果之间的差异。以下是同一查询执行计划中的两个相关行:

复制代码
...
         Estimates: capacity=73 distinct keys=73 lookups=898 hit percent=91.87%
         Hits: 830  Misses: 68  Evictions: 0  Overflows: 0  Memory Usage: 19kB
...

🔧 btree_gin:整数类型的比较运算符

提交: [e2b64fcef35], [fc896821c44]

btree_gin 扩展的用户提供的小便利。

sql 复制代码
CREATE EXTENSION btree_gin;

CREATE TABLE t (a bigint, b text);
INSERT INTO t SELECT random(1,100), random()::text FROM generate_series(1, 100000);

CREATE INDEX idx ON t USING GIN (a, b gin_trgm_ops);
VACUUM ANALYZE t;

SELECT * FROM t WHERE a = 42 AND b LIKE '*42*';

以前,对于此类查询,规划器只会使用列 b 条件的索引,而不会将 a = 42 纳入索引搜索条件,因为列 a 的类型是 bigint,而 42 默认为 int。这需要在查询中显式指定 a = 42::bigint

现在 btree_gin 已得到改进,int2int4int8 将自动转换为适当的类型以供索引使用。

sql 复制代码
EXPLAIN SELECT * FROM t WHERE a = 42 AND b LIKE '*42*';
                             QUERY PLAN                             
--------------------------------------------------------------------
 Bitmap Heap Scan on t  (cost=229.49..233.51 rows=1 width=27)
   Recheck Cond: ((a = 42) AND (b ~~ '*42*'::text))
   ->  Bitmap Index Scan on idx  (cost=0.00..229.49 rows=1 width=0)
         Index Cond: ((a = 42) AND (b ~~ '*42*'::text))
(4 rows)

🚀 pg_upgrade:优化大对象迁移

提交: [161a3e8b682], [3bcfcd815e1]

当从版本 12 及以上版本升级时,带有 --binary-upgrade 参数的 pg_dump 会为大对象生成 COPY 命令,将数据直接插入 pg_largeobject_metadatapg_shdepend 表中。

从这样的转储中恢复比执行 ALTER LARGE OBJECT 命令分配所有权和 GRANT 命令设置权限要快得多。因此,pg_upgrade 升级包含大量大对象的服务器将花费更少的时间。

从版本 16 及更高版本升级(第二个提交)将更快,因为 pg_largeobject_metadata 表文件将像普通用户表文件一样被迁移。

不带 --binary-upgrade 参数的 pg_dump 继续像往常一样使用 SQL 命令导出大对象元数据。


⚡ 优化临时表截断

提交: [78ebda66bf2]

以前截断临时表需要为每个分支(主关系、可见性映射和空闲空间映射)扫描本地缓冲区缓存(temp_buffers)三次。现在一次扫描就足够了。这对于大量使用临时表的应用程序来说是一个非常有价值的优化。

普通表的类似优化早在 PostgreSQL 13 中就已实现。


📐 规划器:Append 和 MergeAppend 节点中的增量排序

提交: [55a780e9476]

规划器现在可以为嵌套在 AppendMergeAppend 中的节点利用增量排序。当嵌套节点可以产生部分排序的数据时,规划器将倾向于增量完成排序,而不是对整个结果集执行完整排序。


🔓 域约束验证不再阻塞 DML 操作

提交: [16a0039dc0d]

ALTER DOMAIN ... VALIDATE CONSTRAINT ... 命令现在使用较轻的 SHARE UPDATE EXCLUSIVE 锁,而不是之前的 SHARE 锁。这允许对使用该域的表进行并发修改而不会阻塞。


⚙️ CHECKPOINT 命令参数

提交: [cd8324cc89a], [bb938e2c3c7], [a4f126516e6], [2f698d7f4b7], [8d33fbacbac]

CHECKPOINT 命令现在支持参数:

sql 复制代码
=# \h checkpoint 
Command:     CHECKPOINT
Description: force a write-ahead log checkpoint
Syntax:
CHECKPOINT [ ( option [, ...] ) ]

where option can be one of:

    FLUSH_UNLOGGED [ boolean ]
    MODE { FAST | SPREAD }

URL: https://www.postgresql.org/docs/devel/sql-checkpoint.html

当启用 FLUSH_UNLOGGED 时,未记录对象(表、索引等)的修改缓冲区将被刷新到磁盘。此参数默认禁用。

此参数有助于在大量使用未记录表时减少服务器重启时间。在关闭服务器之前,可以手动运行 CHECKPOINT,以便在关闭期间后续的检查点完成得更快。以前,未记录对象的脏缓冲区不会被检查点进程刷新到磁盘------这仅在关闭期间发生。现在,通过手动运行带有 FLUSH_UNLOGGED ON 的检查点,可以在服务器停止前卸载更多工作。

为了避免给系统带来过多的写入负载,可以使用另一个新参数 MODE SPREAD 运行预备检查点。检查点将随时间分散进行,并考虑 checkpoint_completion_target 值。这类似于 pg_basebackup 工具中的 --checkpoint={fast|spread} 参数。


📄 COPY FROM:跳过初始行

提交: [bc2f348e87c]

COPY 命令的 header 参数现在除了接受 true/falsematch 之外,还可以接受一个正数值。这个数字指定命令在开始将数据加载到表之前应跳过的初始行数。

sql 复制代码
CREATE TABLE test(id int);

=# COPY test FROM stdin (header 3);
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself, or an EOF signal.
>> first header row
>> second header row
>> third, then data
>> 1
>> 2
>> \.
COPY 2
SELECT * FROM test;
 id 
----
  1
  2
(2 rows)

请注意,在这种情况下,您将无法使用 header match 选项在文件和表之间映射列。


📊 pg_dsm_registry_allocations:动态共享内存使用

提交: [167ed8082f4]

新的系统视图 pg_dsm_registry_allocations 提供有关动态共享内存分配的信息。

sql 复制代码
=# \d pg_dsm_registry_allocations
  View "pg_catalog.pg_dsm_registry_allocations"
 Column |  Type  | Collation | Nullable | Default 
--------+--------+-----------+----------+---------
 name   | text   |           |          | 
 type   | text   |           |          | 
 size   | bigint |           |          | 

相关推荐
青衫码上行3 小时前
高频 SQL 50题(基础版)| 查询 + 连接
数据库·sql·学习·mysql
Anastasiozzzz4 小时前
阿亮随手记:动态条件生成Bean
java·前端·数据库
iameyama4 小时前
python Pandas 开发
数据库
Highcharts.js4 小时前
数据之美:用Highcharts打造专业级弧线图
javascript·数据库·highcharts·图表开发·弧线图
禹凕6 小时前
MySQL——基础知识(正则表达式)
数据库·mysql·正则表达式
SmartBrain7 小时前
FastAPI实战(第三部分):浏览历史的接口开发详解
数据库·人工智能·aigc·fastapi
山岚的运维笔记7 小时前
SQL Server笔记 -- 第77章:文件组
数据库·笔记·sql·microsoft·oracle·sqlserver
有点心急10218 小时前
Python 入门
服务器·数据库·python
独泪了无痕8 小时前
Mac Homebrew 安装 MySQL 指南
数据库·mysql·mac