Postgres 15 beta 2 最近发布了!审查和测试新功能是一种有趣的日常任务。这篇文章着眼于对具有值UNIQUE
的列的约束的改进。虽然唯一约束的细微差别不像使排序更快(这很令人兴奋!)那么华丽,但提高数据库开发人员对数据质量的控制总是一个很好的好处。
Postgres 15 发行说明 总结了这一改进:
“允许唯一约束和索引将 NULL 值视为不同的 (Peter Eisentraut)
以前
NULL
的值总是被索引为不同的值,但现在可以通过使用创建约束和索引来更改UNIQUE NULLS NOT DISTINCT
。”
两种风格UNIQUE
为了了解此更改的作用,我们创建了两个表。该null_old_style
表在 上具有 2 列UNIQUE
约束(val1, val2)
。val2
允许NULL
值。
CREATE TABLE null_old_style ( id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, val1 TEXT NOT NULL, val2 TEXT NULL, CONSTRAINT uq_val1_val2 UNIQUE (val1, val2) );
复制
该null_new_style
表使用新选项:UNIQUE NULLS NOT DISTINCT
. 与上表的唯一区别是为唯一约束添加了新语法。
CREATE TABLE null_new_style ( id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, val1 TEXT NOT NULL, val2 TEXT NULL, CONSTRAINT uq_val1_val2_new UNIQUE NULLS NOT DISTINCT (val1, val2) );
复制
允许数据的变化
在 Postgres 14 和之前的版本中,唯一约束将NULL
值视为不等于其他NULL
值。来自 Postgres 14 文档:
当索引声明为唯一时,不允许具有相同索引值的多个表行。空值不被视为相等。
这与 SQL 标准的处理方式是一致的NULL
,一般情况NULL
是未知的。不可能确定一个未知数是否等于另一个未知数。因为NULL
值之间是未知相等的,所以它们不违反UNIQUE
约束。这通过向表中添加 5 个相同的行来说明null_old_style
。
INSERT INTO null_old_style (val1, val2) SELECT 'Hello', NULL FROM generate_series(1, 5) ; SELECT * FROM null_old_style; id|val1 |val2| --+-----+----+ 1|Hello| | 2|Hello| | 3|Hello| | 4|Hello| | 5|Hello| |
复制
此行为已记录在案并符合预期,甚至是 ANSI SQL 标准的一部分。也就是说,我从来没有真正喜欢过上述行为,因为它不够严格。
使用新NULLS NOT DISTINCT
选项,唯一约束因不允许重复NULL
值而更具限制性。添加一行开始。
INSERT INTO null_new_style (val1, val2) SELECT 'Hello', NULL; SELECT * FROM null_new_style; id|val1 |val2| --+-----+----+ 1|Hello| |
复制
现在尝试使用'Hello'
inval1
和NULL
in添加第二行val2
会导致违反唯一约束。
INSERT INTO null_new_style (val1, val2) SELECT 'Hello', NULL; SQL Error [23505]: ERROR: duplicate key value violates unique constraint "uq_val1_val2_new" Detail: Key (val1, val2)=(Hello, null) already exists.
复制
当然,将值更改val1
为新值将允许NULL
在中添加另一个值val2
。
INSERT INTO null_new_style (val1, val2) SELECT 'World', NULL; id|val1 |val2| --+-----+----+ 1|Hello| | 3|World| |
复制
这符合我认为唯一约束应该如何与空值一起使用的心理模型。
概括
我很高兴看到UNIQUE NULLS NOT DISTINCT
Postgres 15 中的新增功能。这为 Postgres 增加了额外的质量控制级别。这也是一个低影响的更改,因为默认操作将照常继续。
作者:Ryan Lambert
文章来源:https://blog.rustprooflabs.com/2022/07/postgres-15-unique-improvement-with-null