Postgres, MVCC y Bloqueo

8

Tengo una serie de declaraciones SQL que se parecen a lo siguiente:

BEGIN;
SELECT counter FROM table WHERE id=X FOR UPDATE;
REALLY COMPLEX QUERY;
UPDATE table SET counter=Y WHERE id=X;
END;

Me gustaría evitar que se lea el contador mientras recupero su valor, pero según los documentos de Postgres "Los bloqueos de nivel de fila no afectan la consulta de datos; bloquean solo los escritores en la misma fila".

Preguntas:

  1. ¿Cuál es el punto de un bloqueo de fila "exclusivo" si no impide las lecturas? ¿Es solo para evitar que otras transacciones tomen acciones bloqueadas?
  2. Si leo la fila con SELECT ... FOR SHARE, ¿eso logra el mismo efecto que un bloqueo "exclusivo"?
  3. ¿Es posible desactivar MVCC para una tabla / esquema / base de datos y permitir escrituras en el lugar?
Kevin
fuente

Respuestas:

5

a 1) Cualquier otra sesión leerá los datos modificados por su transacción tal como estaban antes de su declaración "INICIAR", siempre que su transacción no se haya confirmado. Tan pronto como se haya confirmado su transacción, leerá el nuevo valor del contador. El punto es que otros no tienen que esperar y siempre verán una base de datos consistente.

a 2), 3) ¿Por qué no lo prueba con "ACCESO EXCLUSIVO"? (ver http://www.postgresql.org/docs/current/static/explicit-locking.html )

EDITAR: Si no le gusta bloquear toda la mesa con un bloqueo "ACCESO EXCLUSIVO", también puede usar un "Bloqueo de aviso" (consulte la sección 13.3.4 en el enlace anterior).

jp
fuente
1

Si las lecturas que desea bloquear son ejecuciones simultáneas de la misma transacción solo con datos diferentes, use una instrucción UPDATE con cláusula de retorno.

Echa un vistazo a los documentos en la declaración ACTUALIZAR. Para responder a su pregunta sobre el punto de un bloqueo de fila exclusivo, es para evitar la inconsistencia de datos de las actualizaciones simultáneas. Los lectores obtienen una vista coherente de la base de datos en todo momento.

Ketema
fuente
1

En el ejemplo de código que proporcionó, todas las lecturas de esa fila verán el valor anterior hasta que se confirme esa transacción.

1) Considere que el ejemplo de código se ejecuta dos veces simultáneamente, con el mismo valor de X. Si la instancia A se ha ejecutado select ... for update, ha bloqueado esa fila hasta que se confirma. La instancia B, haciendo lo mismo, se bloqueará al tratar de tomar el bloqueo de la misma manera. Solo cuando A se compromete, B puede continuar. B recibirá el valor que A dejó en su actualización final.

Si Ydepende de qué valor select ... for updatelea la consulta u otra lectura de la misma en la parte 'compleja', esto tendrá el mismo efecto que si se ejecutara en serie: no se obtiene la condición de carrera donde se obtendrá uno de los resultados descartado.

Si Yes puramente el resultado de consultas complejas en el medio, ejecutarlo en paralelo sin select ... for updateque ambos realicen la misma actualización.

2) for sharepermitirá que continúen otras selecciones en esa fila, pero hará que cualquier otra cosa intente select ... for updateo update ...bloquee hasta que se haga. Si el código de muestra se ejecutó dos veces, al mismo tiempo, se estancarían al llegar a la updatedeclaración, lo que provocaría que uno de ellos se cancelara.

3) No. Hacer esto es peligroso, ya que un lector podría leer un campo medio actualizado. (O lea el resto de un campo actualizado después del inicio de la lectura). También puede romper la coherencia, mostrando al lector un valor actualizado después del inicio de su transacción.

MaHuJa
fuente