如何使用字符串作为PostgreSQL顾问锁的密钥



PostgreSQL中有一种锁定机制,称为顾问锁定。它提供了以下API函数。

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

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

是否可以在PostgreSQL中单独实现这一点,而不需要在应用程序级别将字符串强制转换为整数?

如果想要的目标很难实现,也许我可以使用两个整数来标识表中的行。第二个整数可以是行的主键,但我可以使用哪个整数作为表标识符?

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

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

有一个小问题,因为oid在内部是一个无符号的32位整数,但pg_advisory_lock的双参数形式采用了一个有符号整数。这在实践中不太可能是一个问题,因为在成为问题之前,您需要经历很多OID。

例如

SELECT pg_advisory_lock('mytable'::regclass::integer, 42);

然而,如果您要这样做,那么您基本上是在使用咨询锁来模拟行锁定。那么为什么不直接使用行锁定呢?

SELECT 1
FROM mytable
WHERE id = 42
FOR UPDATE OF mytable;

现在,如果你真的必须使用字符串键,你将不得不接受会有冲突,因为你将使用一个相当小的散列。

PostgreSQL内置了用于哈希联接的哈希函数。它们不是加密散列——它们设计得很快,产生的结果也很小。这就是你为此所需要的。

它们实际上散列为int4,而你真的更喜欢int8,所以你会运行更高的碰撞风险。另一种选择是采用像md5这样的慢速加密哈希并截断它,这太难看了。

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

select pg_advisory_lock( hashtext('fredfred') );

但前提是你的应用程序能够处理这样一个事实,即其他字符串不可避免地会产生相同的哈希,所以你可能会看到一行被"锁定",而不是真正锁定的。

最新更新