並發創建 Postgres 索引時需要什麼類型的鎖?
我知道同時創建索引時,只需要一個SHARE ShareUpdateExclusiveLock 鎖。
但是,在流程開始的一小段時間內是否需要更嚴格的鎖定類型?還是整個操作只需要一個SHARE ShareUpdateExclusiveLock 鎖?
我問是因為我想知道在同時創建索引時設置哪些類型的超時是有利的。
好吧,當文件不足時,可以直接查看程式碼。為了避免將來可能的行號更改,我將提供已發布
PostgreSQL 13.1
(標籤)的連結。REL_13_1
我可能不會描述來自客戶端的命令的整個程式碼路徑。通過語法,我們知道我們需要
IndexStmt
命令節點——並發和非並發創建索引的語法相同。一切有用的開始ProcessUtilitySlow
在這裡,在評論中
case T_IndexStmt
,可以找到問題的直接答案:/* * .... To avoid lock upgrade hazards, it's * important that we take the strongest lock that will * eventually be needed here, so the lockmode calculation * needs to match what DefineIndex() does. */ lockmode = stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock;
一般來說,PostgreSQL 在命令執行期間不會升級鎖。並將採取最終需要的最強鎖。因為
CREATE INDEX CONCURRENTLY
它ShareUpdateExclusiveLock
。不是SHARE
問題中提到的鎖。但讓我們繼續閱讀:
- 在分區表的情況下,
find_all_inheritors
繼承者將獲得相同的鎖定模式。- in
transformIndexStmt
可以找到一些鎖定模式,但是NoLock
-AccessShareLock
它們比ShareUpdateExclusiveLock
- 在
DefineIndex
我們看到另一個提醒:* To avoid lock upgrade hazards, that lock should be at least * as strong as the one we take here.
並決定再次使用 ShareUpdateExclusiveLock 進行並發建構。這部分程式碼明顯很長(仍然沒有規劃器那麼大),但可讀。
我錯過了什麼?大概。因此,讓我們建構帶有
-DLOCK_DEBUG
調試鎖定行為選項的 PostgreSQL,看看會發生什麼:./configure --prefix=/home/melkij/tmp/pgdev/inst --enable-cassert --enable-debug CFLAGS="-ggdb -Og -g3 -fno-omit-frame-pointer -DLOCK_DEBUG" --enable-tap-tests make -sj 4 make install initdb ... pg_ctl start ... # then psql with follow commands create table foo as select generate_series(1,1000) as id; set trace_locks = true; create index concurrently on foo (id); select oid, relname, relkind from pg_class where oid in (16387,16393); # oid | relname | relkind #-------+------------+--------- # 16387 | foo | r # 16393 | foo_id_idx | i
trace_locks
會記錄很多東西,但我們感興趣的是:[vxid:3/62 txid:0] [CREATE INDEX] LOG: LockAcquire: lock [12664,16387] ShareUpdateExclusiveLock [vxid:3/62 txid:0] [CREATE INDEX] LOG: LockAcquire: lock [12664,16387] ShareUpdateExclusiveLock [vxid:3/62 txid:0] [CREATE INDEX] LOG: LockAcquire: lock [12664,16393] AccessExclusiveLock [vxid:3/62 txid:495] [CREATE INDEX] LOG: LockAcquire: lock [12664,16387] ShareUpdateExclusiveLock [vxid:3/63 txid:0] [CREATE INDEX] LOG: LockAcquire: lock [12664,16387] ShareUpdateExclusiveLock [vxid:3/63 txid:0] [CREATE INDEX] LOG: LockAcquire: lock [12664,16393] RowExclusiveLock [vxid:3/64 txid:0] [CREATE INDEX] LOG: LockAcquire: lock [12664,16387] ShareUpdateExclusiveLock [vxid:3/64 txid:0] [CREATE INDEX] LOG: LockAcquire: lock [12664,16393] RowExclusiveLock [vxid:3/64 txid:0] [CREATE INDEX] LOG: LockAcquire: lock [12664,16393] ExclusiveLock [vxid:3/64 txid:0] [CREATE INDEX] LOG: LockAcquire: lock [12664,16393] ExclusiveLock
lock [12664,16387]
這裡的意思是 databaseOID = 12664
,pg_class
OID = 16387
(這些行是從 記錄的LockAcquireExtended
)。所以,我們實際上只
ShareUpdateExclusiveLock
在表本身上獲取。OID=16393
與其他幾個鎖是該命令建立的索引。儘管針對此對象提到了重鎖定級別,但它不會干擾其他查詢。Create index concurrently
命令專門設計用於在執行正常的應用程序查詢時安全工作。