没有选择的Postgres条件唯一约束
Posted
技术标签:
【中文标题】没有选择的Postgres条件唯一约束【英文标题】:Postgres conditional unique constraint without select 【发布时间】:2017-10-04 01:34:55 【问题描述】:我有下表:
汽车:ID、名称、状态
只要我们有一个状态为SOLD
的名称记录,我想对汽车名称实施条件约束。
例子:
1, 'BMW', 'NEW'
2, 'BMW', 'NEW'
3, 'BMW', 'SOLD'
4, 'BMW', 'NEW'
前 3 条记录应该可以正常插入。但是不应该插入第 4 条记录,因为我们现在有一辆状态为 SOLD
的 BMW。
这是我尝试过的:
CREATE UNIQUE INDEX cars_sold ON cars (name) WHERE (status = 'SOLD');
这并不像我希望的那样工作。这只能确保我们不能有 2 个BMW
即SOLD
注意:我可以使用INSERT SELECT
来完成此操作,但此表将变得非常大,因此我想要执行唯一约束的性能。我还看到我可以使用CONSTRAINT CHECK
来做到这一点,但我相信它基本上可以在引擎盖下使用SELECT
。
在没有SELECT
在大桌子上的性能影响的情况下,有没有办法做到这一点?从概念上讲,我似乎总是不得不做一个SELECT
【问题讨论】:
我认为您必须为此使用触发器。数据结构非常奇怪。为什么不直接更新? @GordonLinoff 触发器是否必须在后台运行选择?我真的想避免选择的性能影响,否则我只会做一个插入选择 标准涉及当前记录中不可用的信息。也许使用外部表来跟踪状态。 【参考方案1】:您将无法使用约束来执行此操作,因为约束始终检查数据库的当前状态,并且不考虑应用修改的顺序。
我认为最好使用BEFORE INSERT
触发器来解决问题,该触发器为具有相同名称和状态SOLD
的汽车运行SELECT
语句。无论表有多大,您在问题中创建的唯一部分索引都应该使SELECT
的速度非常快。
【讨论】:
我相信我的约束不需要知道应用修改的顺序。它只需要数据库的当前状态。回到我的例子,当应用数字 4 时,它并不关心应用了哪个订单 1、2、3,它只关心 #3 有一个BMW
状态为 SOLD
。
另外,部分索引对我有什么帮助?是不是因为索引树现在小得多,因为它只包含状态为SOLD
的值?
如果您假设增加id
反映了修改的时间,那么您是对的(但如果存在高并发,请不要指望这一点)。我仍然想不出能反映这一点的约束。部分索引会很快,因为它是唯一的 - 它可以快速命中匹配的叶条目并且不必扫描。以上是关于没有选择的Postgres条件唯一约束的主要内容,如果未能解决你的问题,请参考以下文章