Tarde, me he enfrentado a muchas disputas de bloqueo de fila. La tabla en disputa parece ser una tabla particular.
Esto es generalmente lo que sucede:
- El desarrollador 1 inicia una transacción desde la pantalla frontal de Oracle Forms
- El desarrollador 2 inicia otra transacción, desde una sesión diferente usando la misma pantalla
~ 5 minutos, el extremo frontal parece no responder. La comprobación de sesiones muestra la contención de bloqueo de fila. La "solución" que todos arrojan es matar sesiones: /
Como desarrollador de bases de datos
- ¿Qué se puede hacer para eliminar las contiendas de bloqueo de fila?
- ¿Sería posible averiguar qué línea de un procedimiento almacenado está causando estas contenciones de bloqueo de fila?
- ¿Cuál sería la directriz general para reducir / evitar / eliminar tales problemas que codifican?
Si esta pregunta tiene demasiada información abierta / insuficiente, no dude en editar / hágamelo saber. Haré todo lo posible para agregar información adicional.
La tabla en cuestión está bajo muchas inserciones y actualizaciones, diría que es una de las tablas más ocupadas. El SP es bastante complejo, para simplificar, obtiene datos de varias tablas, lo completa en tablas de trabajo, se producen muchas operaciones aritméticas en la tabla de trabajo y el resultado de la tabla de trabajo se inserta / actualiza en la tabla en cuestión.
La versión de la base de datos es Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit. El flujo de la lógica se ejecuta en el mismo orden en ambas sesiones, la transacción no se mantiene abierta durante demasiado tiempo (o al menos eso creo ), y los bloqueos se producen durante la ejecución activa de las transacciones.
Actualización: el recuento de filas de la tabla es mayor de lo que esperaba, aproximadamente 3.1 millones de filas. Además, después de rastrear una sesión, descubrí que un par de declaraciones de actualización de esta tabla no están utilizando el índice. ¿Por qué es así? No estoy seguro. La columna a la que se hace referencia en la cláusula where está indexada. Actualmente estoy reconstruyendo el índice.
fuente
COMMIT
oROLLBACK
en un tiempo razonable ob) organizar de manera que las mismas personas no siempre quieran la misma fila al mismo tiempo.Respuestas:
No exactamente, pero puede obtener la instrucción SQL que causa el bloqueo y, a su vez, identificar las líneas relacionadas en el procedimiento.
La sección de la Guía de Conceptos de Oracle sobre bloqueos dice: "Una fila está bloqueada solo cuando es modificada por un escritor". Otra sesión que actualice la misma fila esperará la primera sesión
COMMIT
oROLLBACK
antes de que pueda continuar. Para eliminar el problema, puede serializar a los usuarios, pero aquí hay algunas cosas que pueden reducir el problema tal vez al nivel de que no es un problema.COMMIT
más frecuentemente. CadaCOMMIT
lanzamiento se bloquea, por lo que si puede realizar las actualizaciones en lotes, se reduce la probabilidad de que otra sesión necesite la misma fila.UPDATE t1 SET f1=DECODE(f2,’a’,f1+1,f1);
debe reescribirse como el más selectivo (leer menos bloqueos)UPDATE t1 SET f1=f1+1 WHERE f2=’a’;
. Por supuesto, si el cambio de la declaración aún bloqueará la mayoría de las filas en la tabla, entonces el cambio solo tendrá un beneficio de legibilidad.BULK COLLECT ... FORALL
.UPDATE
y elCOMMIT
. Por ejemplo, si el código envía un correo electrónico después de cada actualización, considere poner en cola los correos electrónicos y enviarlos después de confirmar las actualizaciones.SELECT ... FOR UPDATE NOWAIT
oWAIT 2
. Luego puede detectar la imposibilidad de bloquear la fila e informar al usuario que otra sesión está modificando los mismos datos.fuente
Proporcionaré una respuesta desde el punto de vista del desarrollador.
En mi opinión, cuando encuentra una disputa de filas como la que describe, es porque tiene un error en su aplicación. En la mayoría de los casos, este tipo de contención es un signo de una vulnerabilidad de actualización perdida. Este hilo en AskTom explica el concepto de una actualización perdida:
Ha experimentado un efecto secundario desagradable de la actualización perdida: la sesión 2 se puede bloquear porque la sesión 1 aún no se ha comprometido. Sin embargo, el problema principal es que la sesión 2 actualiza ciegamente el registro. Suponga que ambas sesiones emiten la declaración:
Después de ambas declaraciones, las modificaciones de la sesión 1 se han sobrescrito, sin haber notificado a la sesión 2 que la fila había sido modificada por la sesión 1.
La actualización perdida (y el efecto secundario de contención) nunca deberían suceder, son 100% evitables. Debe usar el bloqueo para evitarlos con dos métodos principales: bloqueo optimista y pesimista .
1) Bloqueo pesimista
Desea actualizar una fila. En este modo, evitará que otros modifiquen esta fila solicitando un bloqueo en esa fila (
SELECT ... FOR UPDATE NOWAIT
declaración). Si la fila ya se está modificando, recibirá un mensaje de error, que puede traducir con gracia al usuario final (esta fila está siendo modificada por otro usuario). Si la fila está disponible, realice sus modificaciones (ACTUALIZACIÓN), luego confirme cada vez que se complete su transacción.2) Bloqueo optimista
Desea actualizar una fila. Sin embargo, no desea mantener un bloqueo en esa fila, tal vez porque usa varias transacciones para actualizar la fila (aplicación sin estado basada en la web), o tal vez no desea que ningún usuario mantenga un bloqueo durante demasiado tiempo ( lo que puede provocar que otras personas sean bloqueadas). En ese caso, no solicitará un bloqueo de inmediato. Utilizará un marcador para asegurarse de que la fila no ha cambiado cuando se emitirá su actualización. Puede almacenar en caché el valor de todas las columnas, o puede usar una columna de marca de tiempo que se actualiza automáticamente, o una columna basada en secuencia. Cualquiera sea su elección, cuando esté a punto de realizar su actualización, se asegurará de que el marcador en esa fila no haya cambiado emitiendo una consulta como:
Si la consulta devuelve una fila, realice su actualización. Si no es así, esto significa que alguien ha modificado la fila desde la última vez que la consultó. Deberá reiniciar el proceso desde el principio.
Nota: Si tiene plena confianza en todas las aplicaciones que acceden a su base de datos, puede confiar en una actualización directa para el bloqueo optimista. Puede emitir directamente:
Si la declaración no actualiza ninguna fila, sabe que alguien ha cambiado esta fila y debe comenzar de nuevo.
Si todas las aplicaciones están de acuerdo con este esquema, nunca sería bloqueado por otra persona y evitaría la actualización a ciegas. Sin embargo, si no bloquea la fila de antemano, aún es susceptible al bloqueo indefinido si otra aplicación, trabajo por lotes o actualización directa no implementa un bloqueo optimista. Es por eso que le aconsejo que siempre bloquee la fila, sea cual sea su opción de esquema de bloqueo (el impacto en el rendimiento puede ser insignificante ya que recupera todos los valores, incluido el rowid cuando bloquea la fila).
TL; DR
fuente
Esta respuesta probablemente calificaría para una entrada en The Daily WTF.
Correcto, después de rastrear las sesiones y buscar
USER_SOURCE
, rastreé la causa raízfuente