Postgres中的锁
postgres开发实践中遇到一个问题:
1) A用户在执行一条语句
2) B用户执行语句查询相同的表
会发现B用户始终处于等待状态.
跟踪会发现A进程等待时进程堆栈如下:
#0 LockAcquire (locktag=0x7fffa3ad28f0, lockmode=1, sessionLock=0 '\000', dontWait=0 '\000') at /home/hl/uda/build/../collocated_join/src/backend/storage/lmgr/lock.c:677 #1 0x0000000000799654 in LockRelationOid (relid=57432, lockmode=1) at /home/hl/uda/build/../collocated_join/src/backend/storage/lmgr/lmgr.c:79 #2 0x0000000000531ba1 in RangeVarGetRelidExtended (relation=0xe71da0, lockmode=1, missing_ok=1 '\001', nowait=0 '\000', callback=0x0, callback_arg=0x0) at /home/hl/uda/build/../collocated_join/src/backend/catalog/namespace.c:377 #3 0x00000000004ab49b in relation_openrv_extended (relation=0xe71da0, lockmode=1, missing_ok=1 '\001') at /home/hl/uda/build/../collocated_join/src/backend/access/heap/heapam.c:1141 #4 0x00000000004ab759 in heap_openrv_extended (relation=0xe71da0, lockmode=1, missing_ok=1 '\001') at /home/hl/uda/build/../collocated_join/src/backend/access/heap/heapam.c:1247 #5 0x00000000005a1b2b in parserOpenTable (pstate=0xe72040, relation=0xe71da0, lockmode=1) at /home/hl/uda/build/../collocated_join/src/backend/parser/parse_relation.c:956 #6 0x00000000005a1d7b in addRangeTableEntry (pstate=0xe72040, relation=0xe71da0, alias=0xe71df8, inh=1 '\001', inFromCl=1 '\001') at /home/hl/uda/build/../collocated_join/src/backend/parser/parse_relation.c:1022 #7 0x000000000058b232 in transformTableEntry (pstate=0xe72040, r=0xe71da0) at /home/hl/uda/build/../collocated_join/src/backend/parser/parse_clause.c:429 #8 0x000000000058b625 in transformFromClauseItem (pstate=0xe72040, n=0xe71da0, top_rte=0x7fffa3ad2d38, top_rti=0x7fffa3ad2d34, namespace=0x7fffa3ad2d28) at /home/hl/uda/build/../collocated_join/src/backend/parser/parse_clause.c:640 #9 0x000000000058ab76 in transformFromClause (pstate=0xe72040, frmList=0xe71e58) at /home/hl/uda/build/../collocated_join/src/backend/parser/parse_clause.c:120 #10 0x000000000055a7a3 in transformSelectStmt (pstate=0xe72040, stmt=0xe71e90) at /home/hl/uda/build/../collocated_join/src/backend/parser/analyze.c:939
B进程堆栈如下:
#0 0x00007f110753d627 in semop () from /lib64/libc.so.6 #1 0x0000000000740f01 in PGSemaphoreLock (sema=0x7f11070313f0, interruptOK=1 '\001') at pg_sema.c:421 #2 0x00000000007a2521 in ProcSleep (locallock=0xddec58, lockMethodTable=0xa7c2c0 <default_lockmethod>) at /home/hl/uda/build/../collocated_join/src/backend/storage/lmgr/proc.c:1134 #3 0x000000000079c6b9 in WaitOnLock (locallock=0xddec58, owner=0xe9a4a8) at /home/hl/uda/build/../collocated_join/src/backend/storage/lmgr/lock.c:1623 #4 0x000000000079b57b in LockAcquireExtended (locktag=0x7fffa3ad2130, lockmode=8, sessionLock=0 '\000', dontWait=0 '\000', reportMemoryError=1 '\001') at /home/hl/uda/build/../collocated_join/src/backend/storage/lmgr/lock.c:987 #5 0x000000000079ac15 in LockAcquire (locktag=0x7fffa3ad2130, lockmode=8, sessionLock=0 '\000', dontWait=0 '\000') at /home/hl/uda/build/../collocated_join/src/backend/storage/lmgr/lock.c:677 #6 0x0000000000799654 in LockRelationOid (relid=57432, lockmode=8) at /home/hl/uda/build/../collocated_join/src/backend/storage/lmgr/lmgr.c:79 #7 0x00000000004ab2a5 in relation_open (relationId=57432, lockmode=8) at /home/hl/uda/build/../collocated_join/src/backend/access/heap/heapam.c:1023 #8 0x00000000004ab54c in heap_open (relationId=57432, lockmode=8) at /home/hl/uda/build/../collocated_join/src/backend/access/heap/heapam.c:1189 #9 0x000000000062f0d3 in GetPartitionKeyInfo (pkrelid=57432, attnum=0x7fffa3ad2256, attRangeTypeId=0x7fffa3ad2250) at /home/hl/uda/build/../collocated_join/src/backend/commands/logictablecmds.c:201 #10 0x000000000073d28c in HitForeignTableByCond (rel=0xf76380, rte=0xeb6cb8, ftable=0xf77610, fserver=0xf77940, cond=0xf775d8, oldContext=0xe9a390) at /home/hl/uda/build/../collocated_join/src/backend/optimizer/route/createroute.c:599 #11 0x000000000073d721 in build_foreign_route (rel=0xf76380, rte=0xeb6cb8, cond=0xf775d8) at /home/hl/uda/build/../collocated_join/src/backend/optimizer/route/createroute.c:698 #12 0x00000000006ec7bb in set_foreign_size (root=0xeb6648, rel=0xf76380, rte=0xeb6cb8) at /home/hl/uda/build/../collocated_join/src/backend/optimizer/path/allpaths.c:415 #13 0x00000000006ec4e2 in set_rel_size (root=0xeb6648, rel=0xf76380, rti=2, rte=0xeb6cb8) at /home/hl/uda/build/../collocated_join/src/backend/optimizer/path/allpaths.c:250 #14 0x00000000006ecc33 in set_append_rel_size (root=0xeb6648, rel=0xf75d30, rti=1, rte=0xea56a8) at /home/hl/uda/build/../collocated_join/src/backend/optimizer/path/allpaths.c:623 #15 0x00000000006ec49f in set_rel_size (root=0xeb6648, rel=0xf75d30, rti=1, rte=0xea56a8) at /home/hl/uda/build/../collocated_join/src/backend/optimizer/path/allpaths.c:240
导致这个现象的原因是因为在我们在 解析parse的时候就开始加锁了, 直到portal执行完才将此锁释放。而且用的还是exclusive锁。所以
会导致另外的用户查询不了,解决的方法就是把锁的级别改成读锁。
pg中锁分为不同的等级:
#define NoLock 0 #define AccessShareLock 1 /* SELECT */ #define RowShareLock 2 /* SELECT FOR UPDATE/FOR SHARE */ #define RowExclusiveLock 3 /* INSERT, UPDATE, DELETE */ #define ShareUpdateExclusiveLock 4 /* VACUUM (non-FULL),ANALYZE, CREATE * INDEX CONCURRENTLY */ #define ShareLock 5 /* CREATE INDEX (WITHOUT CONCURRENTLY) */ #define ShareRowExclusiveLock 6 /* like EXCLUSIVE MODE, but allows ROW * SHARE */ #define ExclusiveLock 7 /* blocks ROW SHARE/SELECT...FOR * UPDATE */ #define AccessExclusiveLock 8 /* ALTER TABLE, DROP TABLE, VACUUM * FULL, and unqualified LOCK TABLE */
AccessExclusiveLock 这种级别的锁是为了修改而加的。 等级最低,必须等所有锁释放之后才能操作, 查询时用这个锁就会卡住
可以通过 pg_locks 表来查看锁
postgres=# select * from pg_locks where relation = 57432;
locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid | mode | granted | fastpath
----------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+-----+-----------------+---------+----------
relation | 12652 | 57432 | | | | | | | | 2/24 | 674 | AccessShareLock | t | t