如何使用字符串作为PostgreSQL建议锁的密钥?

Sla*_* II 19 postgresql hash locking

PostgreSQL中有一个称为咨询锁定的锁定机制.它提供以下API函数.

允许我们获得这样一个锁的函数接受一个大整数参数:pg_advisory_lock(key bigint)或两个整数键:( pg_advisory_lock(key1 int, key2 int)第二种形式).

我可以使用什么抽象机制来使用字符串键而不是整数键?也许一些哈希函数能够完成这项工作?

是否可以仅在PostgreSQL中实现它,而无需在应用程序级别将字符串转换为整数?

如果难以实现期望的目标,我可以使用两个整数来标识表中的行.第二个整数可以是行的主键,但是我可以使用什么整数作为表标识符?

Cra*_*ger 20

您已经找到了最可能的候选者:使用表的合成主键和表标识符作为键.

您可以使用表的oid(对象标识符)pg_class来指定表.伪类型的便利性regclass为您查找,或者您可以select c.oid from pg_class c inner join pg_namespace n where n.nspname = 'public' and c.relname = 'mytable'通过模式获取它.

这是一个小问题,因为oid内部是无符号的32位整数,但是两个arg形式pg_advisory_lock采用有符号整数.这在实践中不太可能是一个问题,因为在这个问题出现之前你需要经过很多 OID.

例如

SELECT pg_advisory_lock('mytable'::regclass::integer, 42);
Run Code Online (Sandbox Code Playgroud)

但是,如果你要这样做,你基本上是使用咨询锁来模拟行锁定.那么为什么不使用行锁定呢?

SELECT 1
FROM mytable
WHERE id = 42
FOR UPDATE OF mytable;
Run Code Online (Sandbox Code Playgroud)

现在,如果你真的必须使用字符串键,那么你将不得不接受会发生冲突,因为你将使用相当小的哈希值.

PostgreSQL具有内置的散列函数,用于散列连接.它们不是加密哈希 - 它们被设计得很快并且产生相当小的结果.这就是你为此目的所需要的.

它们实际上哈希到int4,你真的更喜欢int8,所以你的碰撞风险更高.另一种方法是采用像md5这样的慢速加密哈希并截断它,这只是丑陋的.

所以,如果你真的,真的觉得你必须,你可以这样做:

select pg_advisory_lock( hashtext('fredfred') );
Run Code Online (Sandbox Code Playgroud)

...但是,只有当您的应用程序能够应对其他字符串不可避免地产生相同哈希的事实时,您才可能看到一行未被真正锁定的"锁定"行.