Postgresql

如何在表掃描期間將列設置為 NOT NULL 而不鎖定表?

  • June 4, 2020

(以前的問題是: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不用長排他鎖了。

引用自:https://dba.stackexchange.com/questions/267947