页级锁是否会导致试图锁定同一页上的 2 个不同行的 2 个事务之间出现死锁?

Can page level locks cause a deadlock between 2 transactions trying to lock 2 different rows on the same page?

根据postgres docs section 13.3.2

In addition to table and row locks, page-level share/exclusive locks are used to control read/write access to table pages in the shared buffer pool. These locks are released immediately after a row is fetched or updated. Application developers normally need not be concerned with page-level locks, but they are mentioned here for completeness.

我的理解是,我不需要担心我的事务是否足够大,以至于它们可能会锁定足够长的行,以至于 T1 锁定了 P1 上的 R1 并想锁定 P2 上的 R2 但不能这样做是因为 T2 在 P2 上锁定了 R3,并且在锁定 P1 上的 R4 之前不会释放它。

T -> transaction
P -> page
R -> row

这个假设是否正确,或者我应该让我的交易足够短,这样这种锁定不太可能发生吗?

无论您的事务需要多长时间,页面级锁总是持有很短的时间。与其他锁不同,它们在提交之前释放,当它们不再需要时立即释放。

另外,页锁的获取方式总是不能参与死锁(除非PostgreSQL有bug)。

详情:

页面锁定是使用 src/backend/storage/lmgr/lmgr.c 中的 LockPage 函数获取的。目前,它们仅在索引清理期间与 GIN 索引一起使用,当挂起列表集成到主索引中时(函数 ginInsertCleanup in src/backend/access/gin/ginfast.c):元页面被锁定以防止函数并发执行。