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

PostgreSQL 19:第二部分 或 CommitFest 2025-09

来源: habr.com

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

我们继续 PostgreSQL 19 变更回顾系列文章。这一次,我们将看看 2025 年 9 月 CommitFest 中涌现的新特性。

第一次七月 CommitFest 的重点内容可在此处查阅:[2025-07]


📑 目录

  • GROUP BY ALL
  • 窗口函数:NULL 值处理
  • PL/Python 中的事件触发器
  • 更精确的错误信息:错误的过程参数名称
  • random:指定范围内的随机日期/时间
  • encode 和 decode 函数的 base64url 格式
  • 新增 debug_print_raw_parse 参数
  • log_lock_waits 参数现在默认启用
  • pg_stat_progress_basebackup:备份类型
  • vacuumdb:收集分区表的统计信息
  • 缓冲区缓存:使用时钟扫描算法查找空闲缓冲区
  • 查询中的虚拟表别名

🔗 GROUP BY ALL

提交: [ef38a4d9756]

这将让那些不想在 GROUP BY 子句中重新列出所有 SELECT 表达式的人生活更轻松。ALL 关键字自动包含所有不使用聚合函数的 SELECT 表达式。

sql 复制代码
SELECT to_char(actual_departure, 'YYYY'),
       count(*)
FROM flights
GROUP BY ALL
ORDER BY 1;
 to_char | count 
---------+-------
 2025    | 16477
 2026    | 42457
         | 10776
(3 rows)

如果你想在分组中添加一个新表达式,只需将其包含在 SELECT 列表中------无需修改 GROUP BY 子句:

sql 复制代码
SELECT to_char(actual_departure, 'YYYY'),
       status,
       count(*)
FROM flights
GROUP BY ALL
ORDER BY 1;
 to_char |  status   | count 
---------+-----------+-------
 2025    | Arrived   | 16477
 2026    | Arrived   | 42438
 2026    | Departed  |    19
         | Boarding  |     5
         | Scheduled | 10249
         | Delayed   |     9
         | Cancelled |   358
         | On Time   |   155
(8 rows)

不过,并非所有人都同意这一更改。一些人在补丁讨论中表达了强烈反对。他们的主要论点是开发人员应该保持对查询代码的完全控制,而不是依赖系统默认值。然而,由于委员会已经批准将 GROUP BY ALL 纳入 SQL 标准的提案,关于其必要性的进一步辩论已无意义,PostgreSQL 19 将包含此功能。

另请参阅

  • Waiting for SQL:202y: GROUP BY ALL (Peter Eisentraut)


🪟 窗口函数:NULL 值处理

提交: [25a30bbd423], [2273fa32bce]

遵循 SQL 标准,lagleadfirst_valuelast_valuenth_value 函数现在支持跳过 NULL 值。在调用这些窗口函数时,可以指定 IGNORE NULLSRESPECT NULLS(默认值)。

sql 复制代码
SELECT a, b,
       first_value(b) RESPECT NULLS OVER w AS respect_nulls,
       first_value(b) IGNORE NULLS OVER w AS ignore_nulls
FROM (VALUES ('a',NULL),('b',1),('c',2)) AS t(a,b)
WINDOW w AS (ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING);
 a | b | respect_nulls | ignore_nulls 
---+---+---------------+--------------
 a |   |               |            1
 b | 1 |               |            1
 c | 2 |               |            1
(3 rows)

🐍 PL/Python 中的事件触发器

提交: [53eff471c]

事件触发器函数现在可以用 PL/Python 编写。以下是一个在 DDL 操作完成时触发的触发器示例。该触发器仅显示有关已执行命令的信息:

sql 复制代码
CREATE EXTENSION IF NOT EXISTS plpython3u;

CREATE OR REPLACE FUNCTION describe_ddl()
RETURNS event_trigger AS $$
    for row in plpy.cursor("SELECT command_tag, object_identity FROM pg_event_trigger_ddl_commands()"):
        plpy.notice(
            "{}. name: {}".format(
                row['command_tag'],
                row['object_identity']
            )
        )
$$ LANGUAGE plpython3u;

CREATE EVENT TRIGGER after_ddl 
ON ddl_command_end EXECUTE FUNCTION describe_ddl();

让我们测试一下:

sql 复制代码
CREATE TABLE test(id integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY);
NOTICE:  CREATE SEQUENCE. name: public.test_id_seq
NOTICE:  CREATE TABLE. name: public.test
NOTICE:  CREATE INDEX. name: public.test_pkey
NOTICE:  ALTER SEQUENCE. name: public.test_id_seq
CREATE TABLE

🎯 更精确的错误信息:错误的过程参数名称

提交: [83a56419457]

我们有一个带命名参数的函数。

sql 复制代码
CREATE FUNCTION f(a int) RETURNS int LANGUAGE SQL RETURN a;
SELECT f(a=>42);
 f  
----
 42
(1 row)

但是,如果在调用函数时指定了错误的参数名称,我们会收到一条通用的错误信息:

sql 复制代码
18=# SELECT f(b=>42);
ERROR:  function f(b => integer) does not exist
LINE 1: SELECT f(b=>42);
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

这个提示具有误导性。确实存在具有该名称和参数类型的函数,但参数名称不同。PostgreSQL 19 中的错误信息更加精确:

sql 复制代码
19=# SELECT f(b=>42);
ERROR:  function f(b => integer) does not exist
LINE 1: SELECT f(b=>42);
               ^
DETAIL:  No function of that name accepts the given argument names.

📅 random:指定范围内的随机日期/时间

提交: [faf071b5538], [9c24111c4da]

在 PostgreSQL 17 中,random 函数增加了在指定范围内生成均匀分布随机数的能力。现在,日期/时间类型也具备了相同的功能:

sql 复制代码
SELECT random(current_date, current_date + 100);
   random   
------------
 2026-03-23
(1 row)

🔐 encode 和 decode 函数的 base64url 格式

提交: [e1d917182c1]

encodedecode 函数现在支持 base64url 格式,该格式可安全地用于文件名和 URL。

sql 复制代码
SELECT encode(decode('+-/_', 'base64url'), 'base64url');
 encode 
--------
 --__
(1 row)

🐛 新增 debug_print_raw_parse 参数

提交: [06473f5a344]

debug_print_* 参数系列处理查询的调试输出。新增了一个 debug_print_raw_parse 参数用于显示原始解析树。

sql 复制代码
\dconfig debug_print_*
List of configuration parameters
       Parameter       | Value 
-----------------------+-------
 debug_print_parse     | off
 debug_print_plan      | off
 debug_print_raw_parse | off
 debug_print_rewritten | off
(4 rows)

让我们看看它为 COMMIT 命令显示了什么。

sql 复制代码
SET debug_print_raw_parse = on;
SET client_min_messages = 'LOG';

COMMIT;
LOG:  raw parse tree:
DETAIL:  (
   {RAWSTMT 
   :stmt 
      {TRANSACTIONSTMT 
      :kind 2 
      :options <> 
      :savepoint_name <> 
      :gid <> 
      :chain false 
      :location -1
      }
   :stmt_location 0 
   :stmt_len 6
   }
)

WARNING:  there is no transaction in progress
COMMIT

🔒 log_lock_waits 参数现在默认启用

提交: [2aac62be8cb]

长时间的锁被认为是系统运行的问题。记录锁信息应默认启用。

sql 复制代码
\dconfig log_lock_waits
List of configuration parameters
   Parameter    | Value 
----------------+-------
 log_lock_waits | on
(1 row)

💾 pg_stat_progress_basebackup:备份类型

提交: [deb674454c5]

pg_stat_progress_basebackup 视图中新增的 backup_type 列指示正在创建的备份是全量备份 还是增量备份

sql 复制代码
\d pg_stat_progress_basebackup
          View "pg_catalog.pg_stat_progress_basebackup"
        Column        |  Type   | Collation | Nullable | Default 
----------------------+---------+-----------+----------+---------
 pid                  | integer |           |          | 
 phase                | text    |           |          | 
 backup_total         | bigint  |           |          | 
 backup_streamed      | bigint  |           |          | 
 tablespaces_total    | bigint  |           |          | 
 tablespaces_streamed | bigint  |           |          | 
 backup_type          | text    |           |          | 

🧹 vacuumdb:收集分区表的统计信息

提交: [6429e5b771d]

vacuumdb 工具现在在使用 --analyze-only--analyze-in-stages 选项时,除了普通表外,还会收集分区表的统计信息。

以前,收集分区表的统计信息需要在 --table 参数中显式指定它们,这并不总是很方便,尤其是在服务器升级后收集统计信息时。


💿 缓冲区缓存:使用时钟扫描算法查找空闲缓冲区

提交: [2c789405275]

以前,维护一个空闲缓冲区列表来帮助查找缓冲区缓存中的可用缓冲区。现在不再使用此列表;而是采用一种循环遍历所有缓冲区的时钟扫描算法进行搜索。消除空闲缓冲区列表预计将简化未来与 NUMA 支持相关的补丁。

从用户的角度来看,此补丁没有任何改变,可能不值得提及。但是,我们 DBA2 课程中的几个主题讨论了空闲缓冲区列表(缓冲区缓存,内存中锁)。这就是我们将此补丁包含在概览中的原因:它提醒我们,这些主题肯定需要针对 PostgreSQL 19 的课程进行更新。


🏷️ 查询中的虚拟表别名

提交: [585e31fcb], [6f79024df34], [5a170e992a4]

历史上,当查询中未显式指定名称时,规划器会为行集生成奇怪的别名。例如,"VALUES":

sql 复制代码
EXPLAIN SELECT * FROM (VALUES (2),(1));
                         QUERY PLAN                          
-------------------------------------------------------------
 Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=4)
(1 row)

你甚至可以在查询中使用这些别名:

sql 复制代码
SELECT * FROM (VALUES (2),(1) ORDER BY "*VALUES*".column1);
 column1 
---------
       1
       2
(2 rows)

这些名称包括:old, new, "*SELECT*", ANY_subquery, "*MERGE*", "*RESULT*", excluded, unnamed_subquery, unnamed_join, "*GROUP*", "*TLOCRN*", "*TROCRN*", "*SELECT* %d", "*VALUES*", xmltable, json_table

由于潜在的向后兼容性问题,用更有意义的名称替换它们被证明是具有挑战性的。事实证明,即使是 PostgreSQL 的回归测试也包含大量使用此类名称的查询,特别是 "*VALUES*"

最终,只有少数名称被弃用:"*SELECT*""*SELECT* %d""ANY_subquery""*TLOCRN*""*TROCRN*"。它们现在被替换为遵循模式 "unnamed_subquery""unnamed_subquery_%d" 的名称。


相关推荐
fchampion1 小时前
MYSQL自学笔记
数据库·笔记·mysql
XiaoHu02072 小时前
MySQL基础(第一弹)
数据库·c++·mysql
惜分飞2 小时前
rose双机引起文件系统损坏使得数据库异常故障处理---惜分飞
数据库·oracle
fchampion2 小时前
MYSQL分析案例
数据库·mysql
宇擎智脑科技3 小时前
RAG系统数据库架构选型对比:SurrealDB单体方案 vs 多数据库组合方案深度分析
数据库·人工智能·数据库架构
饮长安千年月3 小时前
Linux下的敏感目录
linux·网络·数据库·web安全
web182854825124 小时前
代码诊疗室:破解疑难Bug实战
数据库
数据知道4 小时前
MongoDB 数据库与集合管理:显式创建与隐式创建的区别及生产环境建议
数据库·mongodb·oracle
数据知道5 小时前
MongoDB 的 CRUD 极速上手:insertOne/insertMany 与批量写入的性能差异
数据库·mongodb