如何在表掃描期間將列設置為 NOT NULL 而不鎖定表?
(以前的問題是:Postgres 在設置多列不為空時會使用多列索引嗎?)
通常,當我將列設置為非空時,如果它沒有索引,那麼我首先添加它,以便 postgres 可以(希望)在鎖定表的同時進行表掃描時使用索引,以便表被鎖定更短的時間。
我想設置幾列不為空,如下所示:
alter table foos alter column bar1 set not null alter column bar2 set not null alter column bar3 set not null alter column bar4 set not null;
如果我為這些列創建一個多列索引,postgres 在進行此更改之前掃描鎖定表時會使用它嗎?
CREATE INDEX CONCURRENTLY my_index on foos (bar1, bar2, bar3, bar4);
如果我在 IS NULL(或者,IS NOT NULL)上創建了部分索引怎麼辦?
CREATE INDEX CONCURRENTLY my_index on foos (bar1, bar2, bar3, bar4) where bar1 is null and bar2 is null and bar3 is null and bar4 is null;
另一個 postgresql 貢獻者的另一個答案。
在執行“alter table set not null”期間,PostgreSQL 甚至不會嘗試使用任何索引。它只是沒有實施。
正確執行索引掃描是困難的部分。我們不能只做這樣的查詢
select exists(select from foos where bar1 is null)
來自alter table命令的各種原因。這樣的功能將需要大量程式碼(並且在某些邊緣情況下可能還需要脆弱的程式碼),大量工作,僅適用於有限的案例。開發人員不喜歡的東西。實際上,pgsql-hackers 社區不喜歡 NOT NULL 儲存在系統目錄中的方式。重新設計這部分目錄會更清晰。之後,可以使用短鎖執行 SET NOT NULL NOT VALID 和沒有排他鎖的表驗證。類似於
alter table .. add constraint ... not valid
+alter table .. validate constraint
用於檢查約束或外鍵。但這樣的重新設計工作量更大,沒有人願意這樣做。但我有一個好消息:在 PostgreSQL 12(及更高版本)中,掃描整個表並不是唯一的選擇。
alter table set not null
可以通過現有的檢查約束證明 NOT NULL 的正確性。因此,可以這樣做:-- short-time exclusive lock alter table foos add constraint foos_not_null check (bar1 is not null) not valid; -- seqscan, but without exclusive lock, concurrent sessions can read/write alter table foos validate constraint foos_not_null; -- exclusive lock, but foos_not_null proves: there is no NULL in this column -- so this alter table would be fast alter table foos alter column bar1 set not null; -- not needed anymore alter table foos drop constraint foos_not_null;
那是我的更新檔。是的,這看起來像是一種解決方法。但是,幸運的是,它被合併了,現在可以
set not null
不用長排他鎖了。