PostgreSQL 18 于2025 年 9 月 25 日正式发布。
毫无疑问,最重要的变化是全新的异步 I/O (AIO) 子系统。然而,本文将重点介绍那些将影响开发人员日常工作的功能,首先是原生 UUID v7 支持。
PostgreSQL 18 引入了uuidv7()生成 UUID 版本 7 值的函数。
这项原生支持几乎终结了长期以来关于使用SERIAL/IDENTITY类型还是 UUID 作为主键的争论。UUIDv7 兼具两者的优势:既保留了 UUID 的全局唯一性,又具备序列化键的良好性能。
-- Generate a UUIDv7SELECT uuidv7();-- Create a table using UUIDv7 as primary keyCREATE 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 columnCREATE 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 optionannual_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_salaryFROM employees;
虚拟列的优点:
节省空间:对于不需要物理存储的派生数据,虚拟列消除了冗余的磁盘使用。
动态计算:某些计算受益于在查询时执行,特别是当它们依赖于当前系统状态时。
另一方面,STORED对于很少改变的繁重计算来说,生成的列仍然很有价值,其中重复计算的性能成本超过了存储问题。
但是,正如提交中提到的,存在一些限制。最明显的限制是不能在VIRTUAL生成的列上创建索引。
顺便说一句,PostgreSQL 18 还增加了对逻辑复制(提交、文档)中生成列的支持。此功能也仅适用于STORED生成列。
PostgreSQL 18 增强了RETURNING子句的功能,使其能够在 DML 操作中同时访问旧行值和新行值。
这样一来,就无需再单独执行查询来捕获审计日志中的前后值了。
更新操作
-- Update prices and see both old and new valuesUPDATE productsSET price = price * 1.10WHERE price <= 99.99RETURNINGname,old.price AS old_price,new.price AS new_price,new.price - old.price AS price_change;
冲突时插入
-- Upsert with change trackingINSERT INTO products (name, price) VALUES ('Widget', 25.00)ON CONFLICT (name) DO UPDATE SET price = EXCLUDED.priceRETURNINGname,old.price AS previous_price,new.price AS current_price,(old.price IS NULL) AS is_new_record;
删除操作
-- Track what was deletedDELETE FROM productsWHERE price < 10.00RETURNINGold.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 automaticallySeq 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: 89Buffers: shared hit=12Planning:Buffers: shared hit=156 read=3I/O Timings: shared read=0.024Planning Time: 0.512 msExecution Time: 0.734 ms
pg_get_acl() 用于权限检查
PostgreSQL 18 引入了pg_get_acl()以编程方式检索数据库对象访问控制列表 (ACL) 的功能。如果您曾经花时间调试过那些臭名昭著的ERROR 42501: permission denied消息,那么您一定会喜欢有一种统一的方法来检查对象权限。
以前,故障排除权限需要根据对象类型查询不同的系统目录( pg_class) ,每个系统pg_proc目录都有自己的 ACL 格式。pg_namespacepg_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 aclFROM pg_catalog.pg_shdepend AS sJOIN pg_catalog.pg_database AS dON d.datname = current_database() ANDd.oid = s.dbidJOIN pg_catalog.pg_authid AS aON a.oid = s.refobjid ANDs.refclassid = 'pg_authid'::regclassWHERE s.deptype = 'a';-[ RECORD 1 ]-----------------------------------------type | tableschema | publicname | testtabidentity | public.testtabacl | {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 平台仅提供信息存储空间服务。
请扫描二维码,使用微信支付哦。