2017-07-20 37 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) ;