2012-04-20 12 views
19

Estoy un poco confundido al leer acerca de los bloqueos de PostgreSQL.Bloqueos en PostgreSQL al ejecutar UPDATE

Un ejemplo típico callejón sin salida es:

-- Transaction 1 
UPDATE customer SET ... WHERE id = 1 
UPDATE customer SET ... WHERE id = 2 

-- Transaction 2 
UPDATE customer SET ... WHERE id = 2 
UPDATE customer SET ... WHERE id = 1 

Pero lo que si cambio el código de la siguiente manera:

-- Transaction 1 
UPDATE customer SET ... WHERE id IN (1, 2) 

-- Transaction 2 
UPDATE customer SET ... WHERE id IN (1, 2) 

será una posibilidad de estancamiento aquí?

Esencialmente mi pregunta es: en el segundo caso, ¿PostgreSQL bloquea las filas una a una, o bloquea todo el alcance cubierto por la condición WHERE?

¡Gracias de antemano!

Respuesta

28

En PostgreSQL las filas se bloquearán a medida que se actualicen; de hecho, la forma en que esto funciona es que cada tupla (versión de una fila) tiene un campo de sistema llamado xmin para indicar qué transacción hizo esa tupla actual (por inserción o actualización) y un campo del sistema llamado xmax para indicar qué transacción expiró esa tupla (mediante actualización o eliminación). Cuando accede a los datos, comprueba cada tupla para determinar si está visible para su transacción, verificando su "instantánea" activa con estos valores.

Si está ejecutando una ACTUALIZACIÓN y una tupla que coincida con sus condiciones de búsqueda tiene un xmin que lo haría visible para su instantánea y una xmax de una transacción activa, se bloquea, esperando que se complete esa transacción. Si la transacción que primero actualiza la tupla se revierte, su transacción se activa y procesa la fila; si la primera transacción se compromete, su transacción se activa y toma medidas dependiendo del nivel de aislamiento de la transacción actual.

Obviamente, un punto muerto es el resultado de que esto ocurra a las filas en diferente orden. No hay un bloqueo de nivel de fila en la RAM que se puede obtener para todas las filas al mismo tiempo, pero si las filas se actualizan en el mismo orden, no puede tener el bloqueo circular. Por desgracia, la sintaxis IN(1, 2) sugerido no garantiza que. Diferentes sesiones pueden tener diferentes factores de coste activos, una tarea de "análisis" de fondo puede cambiar las estadísticas para la tabla entre la generación de un plan y el otro, o puede usar un seqscan y verse afectado por la optimización de PostgreSQL que causa un nuevo seqscan para unir uno ya en progreso y "recorrer" para reducir la E/S del disco.

Si realiza las actualizaciones una a la vez en el mismo orden, en el código de la aplicación o con un cursor, entonces tendrá solo bloqueos simples, no interbloqueos. Sin embargo, en general, las bases de datos relacionales son propensas a fallas de serialización, y es mejor acceder a ellas a través de un marco que las reconocerá en base a SQLSTATE y automáticamente volverá a intentar toda la transacción desde el principio. En PostgreSQL un error de serialización siempre tendrá un SQLSTATE de 40001 o 40P01.

http://www.postgresql.org/docs/current/interactive/mvcc-intro.html

+0

¡Gracias! Entonces, mi ejemplo anterior puede provocar un punto muerto (porque no conocemos el orden en el que se procesan las filas en ambas transacciones). – vyakhir

+0

Podría causar un punto muerto, aunque eso sería raro; a diferencia del primer ejemplo (elegir explícitamente diferentes órdenes), donde sería común. Puede descartar un punto muerto mediante la adopción de un bloqueo a nivel de tabla con la fuerza adecuada durante cada transacción que actualice la tabla, pero esa curación puede ser peor que la enfermedad. Ver la sección de doc. A la que hice referencia para más detalles. – kgrittn

+0

¿Pero PostgreSQL libera el bloqueo después de que se haya actualizado la fila, pero toda la instrucción UPDATE aún no ha finalizado? En otras palabras, si tenemos una declaración como ACTUALIZACIÓN ... WHERE id IN (1,2,3,4,5) después de las actualizaciones de postgresql, por ejemplo, fila con id = 1 y continúa con la fila con id = 2, ¿liberará la fila id = 1? En caso afirmativo, ¿de qué forma se ruedan las filas si es necesario? – vyakhir

Cuestiones relacionadas