2017-07-20 38 views
0

我想用下面的查询添加一个唯一约束的表表数据约束,所以查询失败 -添加唯一约束,而忽略现有

ERROR: could not create unique index "events_timestamp_request_session_key"
DETAIL: Key (event_timestamp, request_id, session_id)=(2017-07-05 14:53:25.475246+00, a55df6-8533e322cd-aa9d57-87e2, 132443) is duplicated.

预计会有一些重复,但不幸的是,我不能简单地删除或改变它们。

有什么方法可以根据需要添加约束,而忽略表中现有的数据?

回答

4

您可以使用这个部分索引,它不是一个特别好的解决方案,但它会工作,直到你可以纠正你的旧数据。

喜欢的东西:

CREATE UNIQUE INDEX events_timestamp_request_session_key 
ON events (event_timestamp, request_id, session_id) 
WHERE event_timestamp >= '2017-07-01'::timestamp; 

其中时间是你干净的数据的开始。

where子句将索引限制为只查看具有较新事件时间戳的记录。旧的记录完全从索引中排除,因此不考虑进行唯一性检查。

文件:https://www.postgresql.org/docs/9.6/static/indexes-partial.html

+0

它的工作原理,并迫使这些列的组合是唯一的,所以感谢。展望未来,你知道对查询的影响是什么吗?即每周增加大约300万行,查询速度会比使用唯一约束时慢吗?谢谢。 –

+0

@David Gard。插入会更慢,因为他们不得不维护一个额外的索引。您需要进行基准测试以确定是否会导致您遇到问题。有一点需要考虑的是,因为这是一个部分索引,所以它不会帮助任何你想运行的查询旧数据的查询,所以你可能会发现你自己需要2个索引,一个唯一的索引,非唯一的整个表。 – Gary

+0

感谢您的信息,确实非常有帮助。 –

1

我不认为有这样做的内置方法。但是,您可以使用表达式创建唯一索引。让我假设你在每个表都有一个串行唯一ID:

create unique index unq_events_timestamp_request_session_key 
    on (event_timestamp, request_id, session_id, 
     (case when event_id < 99999 then event_id else -1 end) 
     ); 

的表达实际上是说:“如果该键已经在表中,则忽略它的唯一约束”。

您可以通过消除这些强制所有当前副本的独特约束:

create unique index unq_events_timestamp_request_session_key 
    on (event_timestamp, request_id, session_id, 
     (case when event_id in (1, 2, 3, 5, 8) then event_id 
       else -1 
     end) 
     ); 

这需要研究当前的重复。其实,你也可以做任何与筛选子句:

create unique index unq_events_timestamp_request_session_key 
    on (event_timestamp, request_id, session_id) 
    where event_id > 999999 ; 

create unique index unq_events_timestamp_request_session_key 
    on (event_timestamp, request_id, session_id) 
    where event_id not in (1, 2, 3, 5, 8) ;