database database-design deadlock

database - Puntos muertos en la base de datos



database-design deadlock (6)

Una de las razones clásicas por las que tenemos un punto muerto en la base de datos es cuando dos transacciones están insertando y actualizando tablas en un orden diferente.

Por ejemplo, la transacción A se inserta en la Tabla A y luego en la Tabla B.

Y la transacción B se inserta en la Tabla B seguida de A.

Tal escenario siempre corre el riesgo de un punto muerto en la base de datos (suponiendo que no esté utilizando un nivel de aislamiento serializable).

Mis preguntas son:

  1. ¿Qué tipo de patrones sigue en su diseño para asegurarse de que todas las transacciones se inserten y actualicen en el mismo orden? Un libro que estaba leyendo tenía una sugerencia de que puede ordenar las declaraciones por el nombre de la tabla. ¿Has hecho algo como esto o diferente, lo que obligaría a que todas las inserciones y actualizaciones estén en el mismo orden?

  2. ¿Qué pasa con la eliminación de registros? La eliminación debe comenzar desde las tablas secundarias, y las inserciones deben comenzar desde las tablas primarias. ¿Cómo se asegura de que esto no se convierta en un punto muerto?


  1. Todas las transacciones se están insertando / actualizando en el mismo orden.
  2. Elimina identifique los registros que se eliminarán fuera de una transacción y luego intente eliminarlos en la transacción más pequeña posible, por ejemplo, buscar la clave principal o un elemento similar identificado durante la etapa de búsqueda.
  3. Pequeñas transacciones en general.
  4. La indexación y otros ajustes de rendimiento para acelerar las transacciones y promover las búsquedas de índices a través de las tablas.
  5. Evite las ''tablas calientes'', por ejemplo, una tabla con contadores incrementales para las claves primarias de otras tablas. Cualquier otra configuración de tipo ''centralita'' es arriesgada.
  6. Especialmente si no usa Oracle, aprenda el comportamiento de aspecto de los RDBMS de destino en detalle (optimista / pesimista, niveles de aislamiento, etc.) Asegúrese de no permitir que los bloqueos de filas se escalen a los bloqueos de tabla como lo harán algunos RDMS.

  1. Diseñe cuidadosamente los procesos de su base de datos para eliminar la mayor cantidad posible de transacciones que involucren varias tablas. Cuando he tenido el control de diseño de la base de datos nunca ha habido un caso de interbloqueo para el cual no pude diseñar la condición que lo causó. Eso no quiere decir que no existan y quizás abunden en situaciones fuera de mi limitada experiencia; pero no he tenido pocas oportunidades de mejorar los diseños que causan este tipo de problemas. Una estrategia obvia es comenzar con una tabla cronológica de solo escritura para la inserción de nuevas transacciones atómicas completas sin interdependencias, y aplicar sus efectos en un proceso asíncrono ordenado.

  2. Utilice siempre los niveles de aislamiento predeterminados de la base de datos y la configuración de bloqueo a menos que esté absolutamente seguro de los riesgos en que incurren, y lo haya probado mediante pruebas. Rediseñe su proceso si es posible primero. Luego, imponga el menor aumento en la protección requerida para eliminar el riesgo (y realice una prueba para demostrarlo). No aumente la restricción "por si acaso"; esto a menudo conduce a consecuencias no deseadas, algunas veces del tipo que desea evitar.

  3. Para repetir el punto desde otra dirección, la mayor parte de lo que leerá en este y otros sitios que abogan por la alteración de la configuración de la base de datos para lidiar con los riesgos de transacción y los problemas de bloqueo es engañoso y / o falso, como lo demuestra la forma en que entran en conflicto entre sí. regularmente. Lamentablemente, especialmente para SQL Server, no he encontrado ninguna fuente de documentación que no sea totalmente confusa e inadecuada.


Analizo todas las acciones de la base de datos para determinar, para cada una, si tiene que estar en una transacción de múltiples estados de cuenta, y luego para cada caso, cuál es el nivel de aislamiento mínimo requerido para evitar interbloqueos ... Como usted dijo, la serialización seguramente lo hará asi que...

En general, solo unas pocas acciones de la base de datos requieren una transacción de declaración múltiple en primer lugar, y de ellas, solo unas pocas requieren un aislamiento serializable para eliminar los interbloqueos.

Para aquellos que lo hacen, establezca el nivel de aislamiento para esa transacción antes de comenzar, y restablezca el valor predeterminado después de que se confirme.


Descubrí que una de las mejores inversiones que he hecho para evitar los interbloqueos fue utilizar un Asignador Relacional de Objetos que podría ordenar actualizaciones de la base de datos. El orden exacto no es importante, siempre que cada transacción se escriba en el mismo orden (y se elimine exactamente en el orden inverso).

La razón por la que esto evita la mayoría de los puntos muertos fuera de la caja es que sus operaciones son siempre la tabla A primero, luego la tabla B, luego la tabla C (que quizás depende de la tabla B).

Puede lograr un resultado similar siempre que tenga cuidado con los procedimientos almacenados o el código de acceso de la capa de datos. El único problema es que requiere mucho cuidado para hacerlo a mano, mientras que un ORM con un concepto de Unidad de Trabajo puede automatizar la mayoría de los casos.

ACTUALIZACIÓN: una eliminación se debe ejecutar para verificar que todo es la versión que espera (todavía necesita registrar números de versión o marcas de tiempo) y luego eliminar hacia atrás una vez que todo se verifique. Como todo esto debería suceder en una transacción, la posibilidad de que algo cambie de debajo no debería existir. La única razón para que el ORM lo haga al revés es obedecer los requisitos clave, pero si hace el cheque hacia adelante, tendrá todos los bloqueos que ya necesita en la mano.


Los puntos muertos no son grandes. Solo prepárate para volver a intentar tus transacciones en caso de fallo.

Y manténgalos cortos. Las transacciones cortas que consisten en consultas que tocan muy pocos registros (a través de la magia de la indexación) son ideales para minimizar los interbloqueos: se bloquean menos filas y por un período de tiempo más corto.

Debe saber que los motores de bases de datos modernos no bloquean las tablas; bloquean filas; así que los puntos muertos son un poco menos probables.

También puede evitar el bloqueo mediante el uso de MVCC y el nivel de aislamiento de la transacción CONSISTENT READ: en lugar de bloquear, algunos subprocesos solo verán datos obsoletos.


Su ejemplo solo sería un problema si la base de datos bloqueara la tabla ENTERO. Si su base de datos está haciendo eso ... ejecute :)