PostgreSQL 18 于2025 年 9 月 25 日正式发布。
毫无疑问,最重要的变化是全新的异步 I/O (AIO) 子系统。然而,本文将重点介绍那些将影响开发人员日常工作的功能,首先是原生 UUID v7 支持。
PostgreSQL 18 引入了uuidv7()
生成 UUID 版本 7 值的函数。
这项原生支持几乎终结了长期以来关于使用SERIAL/IDENTITY
类型还是 UUID 作为主键的争论。UUIDv7 兼具两者的优势:既保留了 UUID 的全局唯一性,又具备序列化键的良好性能。
-- Generate a UUIDv7
SELECT uuidv7();
-- Create a table using UUIDv7 as primary key
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT uuidv7(),
customer_id INT,
total DECIMAL(10,2),
created_at TIMESTAMP DEFAULT NOW()
);
生成列最初是在 PostgreSQL 12 时开始引入的,但当时只提供了STORED
选项,这意味着生成的列在写入时会存储并占用磁盘空间。添加STORED
生成的列将重写整个表。
PostgreSQL 18 引入了该VIRTUAL
选项,并将其作为生成列的默认行为。这些列在读取时计算其值,而不是在写入时。这是一种更常见的方法,将其作为默认行为可以使 PostgreSQL 与其他主流数据库保持一致。
-- Create table with virtual generated column
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
salary DECIMAL(10,2),
-- You can also skip VIRTUAL since it's the default option
annual_salary DECIMAL(12,2) GENERATED ALWAYS AS (salary * 12) VIRTUAL
);
-- Insert data (generated columns are computed automatically)
INSERT INTO employees (first_name, last_name, salary) VALUES
('John', 'Doe', 5000.00),
('Jane', 'Smith', 6500.00);
SELECT first_name, last_name, salary, annual_salary
FROM employees;
虚拟列的优点:
节省空间:对于不需要物理存储的派生数据,虚拟列消除了冗余的磁盘使用。
动态计算:某些计算受益于在查询时执行,特别是当它们依赖于当前系统状态时。
另一方面,STORED
对于很少改变的繁重计算来说,生成的列仍然很有价值,其中重复计算的性能成本超过了存储问题。
但是,正如提交中提到的,存在一些限制。最明显的限制是不能在VIRTUAL
生成的列上创建索引。
顺便说一句,PostgreSQL 18 还增加了对逻辑复制(提交、文档)中生成列的支持。此功能也仅适用于STORED
生成列。
PostgreSQL 18 增强了RETURNING
子句的功能,使其能够在 DML 操作中同时访问旧行值和新行值。
这样一来,就无需再单独执行查询来捕获审计日志中的前后值了。
更新操作
-- Update prices and see both old and new values
UPDATE products
SET price = price * 1.10
WHERE price <= 99.99
RETURNING
name,
old.price AS old_price,
new.price AS new_price,
new.price - old.price AS price_change;
冲突时插入
-- Upsert with change tracking
INSERT INTO products (name, price) VALUES ('Widget', 25.00)
ON CONFLICT (name) DO UPDATE SET price = EXCLUDED.price
RETURNING
name,
old.price AS previous_price,
new.price AS current_price,
(old.price IS NULL) AS is_new_record;
删除操作
-- Track what was deleted
DELETE FROM products
WHERE price < 10.00
RETURNING
old.name AS deleted_product,
old.price AS deleted_price;
默认情况下使用 BUFFERS 执行 EXPLAIN ANALYZE
PostgreSQL 18 改进了该EXPLAIN
命令,以自动提供更详细的查询执行信息。
EXPLAIN ANALYZE
现在默认包含缓冲区使用情况信息,无需再添加该BUFFERS
选项。此默认行为可帮助开发人员发现原本可能被忽视的 I/O 性能问题:
postgres=# EXPLAIN ANALYZE SELECT * FROM users WHERE age > 25;
-- PostgreSQL 18: BUFFERS included automatically
Seq Scan on users (cost=0.00..18.75 rows=125 width=64) (actual time=0.029..0.087 rows=178 loops=1)
Filter: (age > 25)
Rows Removed by Filter: 89
Buffers: shared hit=12
Planning:
Buffers: shared hit=156 read=3
I/O Timings: shared read=0.024
Planning Time: 0.512 ms
Execution Time: 0.734 ms
pg_get_acl() 用于权限检查
PostgreSQL 18 引入了pg_get_acl()
以编程方式检索数据库对象访问控制列表 (ACL) 的功能。如果您曾经花时间调试过那些臭名昭著的ERROR 42501: permission denied
消息,那么您一定会喜欢有一种统一的方法来检查对象权限。
以前,故障排除权限需要根据对象类型查询不同的系统目录( pg_class
) ,每个系统pg_proc
目录都有自己的 ACL 格式。pg_namespace
pg_attribute
该pg_get_acl()
函数提供了一个统一的接口,用于从任何数据库对象中检索 ACL,无需记住针对不同对象类型查询哪个目录。
postgres=# SELECT
(pg_identify_object(s.classid,s.objid,s.objsubid)).*,
pg_catalog.pg_get_acl(s.classid,s.objid,s.objsubid) AS acl
FROM pg_catalog.pg_shdepend AS s
JOIN pg_catalog.pg_database AS d
ON d.datname = current_database() AND
d.oid = s.dbid
JOIN pg_catalog.pg_authid AS a
ON a.oid = s.refobjid AND
s.refclassid = 'pg_authid'::regclass
WHERE s.deptype = 'a';
-[ RECORD 1 ]-----------------------------------------
type | table
schema | public
name | testtab
identity | public.testtab
acl | {postgres=arwdDxtm/postgres,foo=r/postgres}
虽然不像新的 AIO 那样引人注目,但这些生活质量的改进使日常开发变得更容易,而且更清晰的界面。
可以看到,pg_get_acl()函灵敏
不仅使人类开发人员受益,也将使 AI 代理受益。作者:天舟
地址:
https://www.bytebase.com/blog/what-is-new-in-postgres-18-for-developer/
本篇文章为 @ 场长 创作并授权 21CTO 发布,未经许可,请勿转载。
内容授权事宜请您联系 webmaster@21cto.com或关注 21CTO 公众号。
该文观点仅代表作者本人,21CTO 平台仅提供信息存储空间服务。
请扫描二维码,使用微信支付哦。