postgresql hash locking

¿Cómo uso la cadena como clave para el bloqueo de avisos de PostgreSQL?



hash locking (1)

Hay un mecanismo de bloqueo en PostgreSQL llamado bloqueo de asesoría . Proporciona las siguientes funciones de la API .

La función que nos permite obtener dicho bloqueo acepta un gran argumento entero: pg_advisory_lock(key bigint) o dos claves de enteros: pg_advisory_lock(key1 int, key2 int) (segunda forma).

¿Qué mecanismo de abstracción puedo usar para poder usar claves de cadena en lugar de las enteras? ¿Tal vez algunas funciones de hash podrán hacer el trabajo?

¿Es posible implementar esto únicamente en PostgreSQL sin la necesidad de convertir una cadena a un entero en el nivel de la aplicación?

Si el objetivo deseado es difícil de lograr, tal vez pueda usar dos enteros para identificar la fila en la tabla. El segundo entero podría ser una clave primaria de la fila, pero ¿qué entero puedo usar como identificador de tabla?


Ya ha encontrado al candidato más probable: usar una clave primaria sintética de una tabla más un identificador de tabla como clave.

Puede usar el oid (identificador de objeto) de la tabla de pg_class para especificar la tabla. La regclass conveniencia al pseudo-tipo regclass busca esto para ti, o puedes select c.oid from pg_class c inner join pg_namespace n where n.nspname = ''public'' and c.relname = ''mytable'' para obtenerlo esquema.

Hay un pequeño problema, porque oid es internamente un entero de 32 bits sin firmar, pero la forma de dos pg_advisory_lock de pg_advisory_lock toma un entero con signo. Es probable que esto no sea un problema en la práctica, ya que debe pasar por muchos OID antes de que se trate de un problema.

p.ej

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

Sin embargo, si va a hacer eso, básicamente está emulando el bloqueo de filas utilizando bloqueos de advertencia. Entonces, ¿por qué no usar el bloqueo de filas?

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

Ahora, si realmente tuviste que usar una clave de cadena, tendrás que aceptar que habrá colisiones porque usarás un hash bastante pequeño.

PostgreSQL tiene funciones hash integradas que se usan para uniones hash. No son hash criptográficos, están diseñados para ser rápidos y producen un resultado bastante pequeño. Eso es lo que necesitas para este propósito.

De hecho, tienen que ver con int4, y realmente preferirías int8, por lo que corres un riesgo aún mayor de colisiones. Sin embargo, la alternativa es tomar un hash criptográfico lento como md5 y truncarlo, y eso es simplemente feo.

Entonces, si realmente, realmente sientes que debes, podrías hacer algo como:

select pg_advisory_lock( hashtext(''fredfred'') );

... pero solo si su aplicación puede hacer frente al hecho de que es inevitable que otras cadenas puedan producir el mismo hash, por lo que puede ver una fila como "bloqueada" que no está realmente bloqueada.