Tengo el siguiente script SQL que establece el valor de secuencia correspondiente al valor máximo de la columna ID:
SELECT SETVAL('mytable_id_seq', COALESCE(MAX(id), 1)) FROM mytable;¿Debería bloquear 'mytable' en este caso para evitar cambiar la ID en una solicitud paralela, como en el ejemplo a continuación?
request #1 request #2 MAX(id)=5 inserted id 6 SETVAL=5¿O setval(max(id)) es una operación atómica?
Su sospecha es correcta, este enfoque está sujeto a las condiciones de carrera.
Pero bloquear la tabla no ayudará, porque no evitará que una transacción concurrente obtenga nuevos valores de secuencia. Esta transacción se bloqueará mientras la mesa esté bloqueada, pero felizmente continuará insertándose una vez que el bloqueo desaparezca, utilizando un valor de secuencia que obtuvo mientras la mesa estaba bloqueada.
Si fuera posible bloquear secuencias, esa podría ser una solución, pero no es posible bloquear secuencias.
Se me ocurren dos soluciones:
Elimine todos los privilegios en la secuencia mientras la modifica, de modo que las solicitudes simultáneas a la secuencia fallen. Eso provoca errores, por supuesto.
La forma pragmática: usar
SELECT SETVAL('mytable_id_seq', COALESCE(MAX(id), 1) + 100000) FROM mytable;Aquí 100000 es un valor que es con seguridad mayor que las filas de números que podrían insertarse mientras se ejecuta la operación.