PostgreSQL Internals之路 Part-III 第14章 其它各类锁

文摘   科技   2024-10-12 12:05   北京  


微信群:数据库Hacker,  已超200人,无法通过扫描直接加入。需要入群的朋友,请直接微信联系我(个人微信:_iihero),标上您的全名以及兴趣领域作为备注。

14. 其它各类锁

14.1 非对象锁

对一个不是关系的资源加锁,PG使用对象类型[1]的重量级锁。你可以对存储在系统目录中的任何对象加锁:表空间,订阅,命名空间,角色,策略,枚举数据类型等等。

让我们开启一个事务,建一张表:

internals=# BEGIN;
BEGIN
internals=*# CREATE TABLE example(n integer);
CREATE TABLE

现在我们看下pg_locks表中的非关系锁:

SELECT database,
(
SELECT datname FROM pg_database WHERE oid = database
AS dbname,
classid,
(
SELECT relname FROM pg_class WHERE oid = classid
AS classname,
objid,
mode,
granted
FROM pg_locks
WHERE locktype = 'object'
AND pid = pg_backend_pid() \gx

-[ RECORD 1 ]--------------
database  | 33060
dbname    | internals
classid   | 2615
classname | pg_namespace
objid     | 2200
mode      | AccessShareLock
granted   | t

锁资源由下边三个值定义:

database --- 包含被锁对象的数据库的ID (可能是0,如果该对象是整个cluster的公共对象)

classid --- pg_class列出的oid, 与系统目录表中定义该资源类型相对应的名字

objid --- 系统目录表中列到的oid,被classid引用

database值指向的是数据库internals的值;它是当前会话连接的数据库。classid列指向的是表:pg_namespace,列的是schema。

我们现在可以解开objid:

SELECT nspname FROM pg_namespace WHERE oid = 2200;
nspname
−−−−−−−−−
public
(1 row)

现在, PG将public schema锁定,以确保在该事务执行的时候没有人可以删除它。

类似的,对象的删除需要对象自身的排它锁,也需要它所依赖的对象[2]的排它锁。

=> ROLLBACK;

14.2 关系扩展锁

随着关系中元组数量的增长,PG会把新行尽量插到已获得的页的空闲空间里。但是也很明确的是在某些时候,它还是不得不添加新页,也就是说,扩展该关系。从物理布局来看,新页会添加到对应文件的末尾(反过来,可以导致创建一个新文件)。

同一时候,新页只能被一个进程添加,该操作被一个特殊的扩展类型重量级锁所保护。这样的锁,同样用于索引的回收,以禁止在索引扫描的时候添加新的页。

关系扩展锁,与我们目前看到的还是有些不同:

  • 它们会在扩展创建完后立即释放,不用等待事务完成。

  • 它们不会导致死锁,因此它们也不会被包含到等待图里。

    然而,如果扩展关系的过程所花时间超过deadlock_timeout,死锁检测仍会执行。这不是一个常见的场景,但是如果大量进程并发的执行多个插入,它就有可能发生。在这种情形下,该检查可能被调多次,几乎要瘫痪正常的系统运行。

    为将这种风险最小化,堆文件会立即扩展多个页面(v9.6,  与等待锁的进程数量成比例, 但不超过每个操作512页[3])。这个规则的一个例外是B-树索引文件,它每次只扩展一个页面[4]

14.3 页锁

页类型的页级重量级级只适用于GIN索引,并只用于下述情形。

GIN索引可以加速对组合值中的元素的查找,如文本文档中的词的检索。它们可以粗略的描述成存储分离的词的而不是整个文档的B-树。当一篇新文档添加进来,索引会整个更新,以包含这个文档中出现的每个单词。

为改善性能,GIN索引允许延迟插入,通过存储参数fastupdate(默认是on)可以启用这个功能。新词首先添加到一个未排序的延迟列表里,过一会儿后所有累积的条目会移到主索引结构里。因为不同的文档可能包含相同的单词,该方法被证明是相当划算的。

为避免多个进程并发的传输单词,索引的元页面会被排它锁锁住,直到所有单词从延迟表移到主索引那里。这个锁不会干扰常规索引的使用。

就像关系扩展锁一样,页锁会在任务完成时立即释放,不用等待事务结束,因此它们永远不会造成死锁。

数据库杂记
数据库技术专家,PostgreSQL ACE,SAP HANA,Sybase ASE/ASA,Oracle,MySQL,SQLite各类数据库, SAP BTP云计算技术, 以及陈式太极拳教学倾情分享。出版过三本技术图书,武术6段。
 最新文章