En cualquier aplicación de Base de Datos
multiusuario es inevitable que, eventualmente, dos usuario deseen trabajar
sobre a misma fila al mismo tiempo. Esto es lógicamente imposible, y la Base de
Datos debe asegurarse de que se trata de una imposibilidad física. El principio
de aislamiento de transacción – la I de la prueba ACID – require que la Base de
Datos garantice que una sesión no puede ver o ser afectada por cualquier otra
sesión hasta que la transacción es completada. Para lograr esto, la Base de
Datos debe serializar el acceso simultáneo a los datos; debe asegurarse que
incluso varias sesiones han solicitado acceso a la misma fila, que en realidad
hacen cola y esperar turno.
Serialización de acceso concurrente es lograda
por los mecanismos de bloqueo de registro y tablas. Bloqueo en una Base de
Datos Oracle es completamente automático. En términos generales, los problemas
surgen solamente si el software intenta interferir con el mecanismo de bloqueo
automático con código mal escrito, o si el análisis de negocio es deficiente
y los resultados en un modelo de negocio
donde las sesiones colisionan.
Bloqueos
Compartidos y Exclusivos.
El nivel estándar de bloqueo en una Base de
Datos Oracle garantiza el nivel más alto posible de la concurrencia. Esto
significa que si una sesión está actualizando una fila, la fila uno es bloqueado,
nada más. Por otra parte, la fila es
bloqueada para prevenir que otras sesiones la actualicen – otras sesiones
pueden leer en cualquier momento. El bloqueo se mantiene hasta que la
transacción es completada, ya sea con un COMMIT o un ROLLBACK. Esto es un
Bloqueo exclusivo: La primera sesión solicita el Bloqueo sobre la Fila
obtenida, y cualquier otra sesión solicita el acceso de escritura pero debe
esperar. Acceso de lectura es permitido – aunque si la fila ha sido actualizada
por la sesión que bloqueo, como usualmente será el caso, entonces cualquier
lectura implica el uso de Datos Undo para asegurarse que las sesiones que leen
no vean cualquier cambio sin confirmar (uncommitted).
Solo una sesión puede tomar un bloqueo
exclusivo sobre una fila, o una tabla completa, a la vez – pero los bloqueos
compartidos pueden tomar sobre el mismo
objeto por varias sesiones. No tendría ningún sentido tomar un Bloqueo
compartido sobre una fila, porque el único propósito de un bloqueo de fila es
para obtener el acceso exclusivo para modificar la fila. Bloqueos compartidos
son tomados sobre tablas completas, y muchas sesiones pueden tener un bloqueo
compartido sobre la misma tabla. El propósito de tomar un bloqueo compartido
sobre una tabla es para evitar que otra sesión adquiera bloqueo exclusivo sobre
la tabla: usted no puede obtener un bloqueo exclusivo si alguien ya tiene un
bloqueo compartido. Bloqueos exclusivos sobre tablas son requeridos para ejecutar
declaraciones DDL. Usted no puede emitir una declaración que modifique un
objeto (por ejemplo, eliminar una columna de una tabla) si otra sesión ya tiene
un bloqueo compartido sobre la tabla.
Para ejecutar DML sobre filas, una sesión debe
adquirir bloqueo exclusivo sobre las filas a ser cambiadas y bloqueo compartido
sobre las tablas que contiene las filas. Si otra sesión ya tiene bloqueo
exclusivo sobre las filas, la sesión se colgara hasta que los bloqueos sean
liberados por un COMMIT o un ROLLBACK. Si otra sesión ya tiene un bloqueo
compartido sobre la tabla y bloqueo exclusivo sobre otras filas, que no es un
problema. Un bloqueo exclusivo sobre la tabla sería, pero el mecanismo de
bloqueo por defecto no bloquea todas las tablas a menos que sea necesario por
declaraciones DDL.
En el
Trabajo.
Es posible que la demanda de un bloqueo
exclusivo sobre una tabla completa, pero esto tener que ser solicitado
específicamente y programadores deben tener una buena razón para hacerlo.
Todas las declaraciones DML requieren por lo
menos dos Bloqueos: un bloqueo exclusivo sobre cada fila a afectar y un bloqueo
compartido sobre la tabla que contiene las filas. El bloqueo exclusivo impide
que otra sesión interfiera con la fila, y el bloqueo compartido previene que
otra sesión de cambiar la definición de la tabla con una declaración DDL. Estos
bloqueos son solicitados automáticamente. Si una declaración DML no puede
adquirir el bloqueo exclusivo de la fila que necesita, entonces se colgara
hasta que los obtenga.
Para ejecutar comandos DDL requiere un bloqueo
exclusivo sobre el objeto concerniente. Este no puede ser obtenido hasta que
todas las transacciones DML contra la tabla hayan finalizado. Liberando de esta
manera tanto bloqueo exclusivo y bloqueo compartido. El bloqueo exclusivo
requerido por cualquier declaración DDL es solicitado automáticamente, pero si
no puede ser obtenido – por lo general, debido a que otra sesión ya tiene el
bloqueo compartido concedido por DML – entonces la declaración terminara con un
error inmediatamente.
El
mecanismo de Encolamiento (Enqueue)
Solicitudes para bloqueos son encoladas. Si
una sesión solicita un Bloqueo y no puede obtenerlo porque otra sesión ya tiene
la fila o objeto bloqueado, la sesión esperara. Puede ser que varias sesiones
esperen para acceder a la misma fila o objeto – en ese caso, Oracle no perderá
de vista el orden en que las sesiones solicitaron el bloqueo. Cuando la sesión
con el bloqueo libera la siguiente sesión será concedida y así sucesivamente.
Esto es conocido como el mecanismo de enqueue.
Si usted no quiere una sesión que haga cola,
si no puede obtener un bloqueo, la única forma para evitar esto es el uso de
WAIT o NOWAIT del comando SELECT…FOR UPDATE. Un SELECT normal siempre tendrá
éxito, porque SELECT no requiere bloqueo – pero una declaración DML se
bloqueara. El comando SELECT…FOR UPDATE seleccionara filas y bloquea en modo exclusivo.
Si cualquiera de las filas están
bloqueadas ya, la declaración SELECT…FOR UPDATE será encolada y la sesión se
colgara hasta que el bloqueo sea liberado, al igual que una declaración DML. Para
evitar que la sesión se cuelgue, utilizar
SELECT…FOR UPDATE NOWAIT o SELECT…FOR UPDATE WAIT <n>, donde
<n> es el numero de segundos. Teniendo obtenido los bloqueos con
cualquiera de las opciones de SELECT…FOR UPDATE, usted puede entonces emitir
comandos DML sin posibilidad de colgar la sesión.
En el
Trabajo.
Es posible agregar las palabras SKIP LOCKED a
un SELECT FOR UPDATE, que regresara y bloqueara solo las filas que no son
trabadas por otra sesión. Este comando existía con versiones anteriores, pero
solo soportado desde la versión 11g.
Contención
de Bloqueos
Cuando una sesión solicita un bloqueo sobre
una fila o un objeto y no puede obtenerlo porque otra sesión tiene un bloqueo
exclusivo sobre la fila u objeto, se colgara. Esta es la contención de Bloqueo,
y puede causar que el rendimiento de la base de datos se deteriore
terriblemente como todas las sesiones de la cola están a la espera de los
bloqueos. Alguna contención de bloqueo puede ser inevitable, como resultado de
la actividad normal: la naturaleza de la aplicación puede ser que diferentes usuarios
requieran acceder a la misma información. Pero en muchos casos, la contención
de bloqueos es causada por diseño de programas y sistemas.
La base de datos Oracle proporciona utilidades
para detectar contención de bloqueos, y también es posible resolver el problema
en una emergencia. Un caso especial de contención de bloqueo es el deadlock
(punto muerto), que siempre se resuelve automáticamente por la misma base de
datos.
En el
Trabajo
La contención de Bloqueo es una razón común
para una aplicación que funciona bien bajo pruebas de rutina para detener la
producción cuando se va y el número de sesiones concurrente aumenta, esto no es
culpa del DBA pero estar preparados para detectar tales problemas.
Las causas
de la contención de bloqueo.
Puede ser que la naturaleza del negocio es tal
que los usuarios requieren acceso de escritura a las mismas filas, al mismo
tiempo. Si esto es factor limitante en el rendimiento del sistema, la única
solución es una reingeniería de procesos, para desarrollar un modelo más
eficiente. Pero aunque algunos bloqueos es una parte necesaria del
procesamiento de datos del negocio. Hay algunas fallas en el diseño de
aplicaciones que puede agravar el problema.
Transacciones de larga duración causaran esto
problemas. Un caso obvio es donde un usuario actualiza una fila y luego no
confirma el cambio. Tal vez ni siquiera se va a almorzar, deja la transacción
sin terminar. No se puede evitar que esto ocurra si los usuarios tienen acceso
a la base de datos con las herramientas tales como SQL*PLUS, pero nunca debe
ocurrir con un software bien escrito. La aplicación debe tener cuidado que un
bloqueo solo se impone antes que se produzca una actualización y liberar
inmediatamente.
Mal escritos los procesos batch pueden también
causar problemas, si están codificados como transacciones larga. Consideremos
el caso de un libro de contabilidad: es una imposibilidad lógica en términos de
contabilidad para el libro que en parte en un periodo y en parte de otro, para
la renovación de fin de mes para el siguiente periodo es una transacciones de
negocio. Esta transacción puede involucrar millones de actualizaciones de filas de miles de tablas, y tomar horas
para completarse. Si la rutina se codifica como una transacción con un commit
en el fin, millones de registros serán bloqueados por horas – pero en términos
contables esto es lo que debería suceder. Un buen diseño serie evitar el
problema mediante la actualización de filas en grupos, con commit regulares –
pero los programadores también tendrán que hacerse cargo de simular lectura
consistente a través de las transacciones y manejar la situación donde el
proceso falle y partir de allí. Si se trata de una transacción, esto no sería
un problema: la base de datos realizara un rollback. Si se trata de muchas
transacciones pequeñas, tendrá que manejar un libro mayor que es la mitad de un
periodo u la mitad de otro. Estas consideraciones no deben ser un problema los
programadores deben tener en cuenta que las transacciones de largo impacto en
la usabilidad del sistema y el diseño de sus sistemas en consecuencia.
Productos de terceros procesos usuario pueden
establecer un nivel de bloqueo alto. Por ejemplo, hay algunas aplicaciones de
desarrollo que siempre hacen SELECT…FOR UPDATE para evitar la necesidad de
volver a consultar los datos y verificar los cambios. Algunos otros productos
no pueden hacer bloqueo a nivel de fila: si un usuario desea actualizar una
fila, la herramienta bloquea un grupo de filas – tal vez decenas e incluso
centenas. Si su aplicación software es
escrita con herramientas tales como estas, la base de datos Oracle, simplemente
hará lo que le diga que hacer: que impondrá numerosos bloqueos que son
innecesarios en términos de negocio. Si usted sospecha que el software es la
aplicación más seguros de lo necesario, investigar si tiene opciones de
configuración para cambiar este comportamiento.
Por último asegurarse de que los programadores
son conscientes de las capacidades de la base de datos. Un problema común es
repetir lecturas. Considera este ejemplo:
SQL> select * from regions;
REGION_ID
REGION_NAME
----------
-------------------------
1
Europe
2
Americas
3
Asia
4
Middle East and Africa
SQL>
select count(*) from regions;
COUNT(*)
----------
5
Como puede ser posible? La primera consulta
(el reporte detallado) muestra cuatro filas, entonces las segunda consulta (el
resumen) muestra cinco. El problema es que durante la ejecución de la primera
consulta, otra sesión inserta y confirma la quinta fila. Una manera de salir de
esto sería bloquear las tablas durante la ejecución de informes, lo que
causaría colgar otras sesiones. Una forma más sofisticada seria utilizar la
declaración SET TRANSACTION READ ONLY. Esto garantiza (sin imponer bloqueos)
que la sesión no vea ningún DML sobre cualquier
tabla, confirmadas o no, hasta que se termina la transacción de sólo lectura
con un COMMIT o ROLLBACK. El mecanismo se basa en el uso de segmentos de
deshacer.
Detectando
y Resolviendo Contención de Bloqueo.
Hay vistas que le dirán que está pasando con
los Bloqueos en la Base de Datos, pero en este caso donde incluso los
administradores de Bases de Datos a menudo prefieren utilizar las herramientas
gráficas. Para alcanzar administración de Bloqueos con Database Control, tome
la ficha Performance desde la pagina principal de la Base de Datos, luego el
Link Bloqueos de Instancia de la sección Monitoring. La figura 10-5 muestra la
ventana Database Locks, con Blocking Locks Seleccionado. Puede haber cualquier número
de bloqueos dentro de la Base de Datos, pero generalmente solo los bloqueos que
están causando que las sesiones se cuelguen son de interés. Estos son conocidos
como Blocking Locks.
En la figura 10-5, hay dos problemas. La
sesión numero 116, logueado como usuario SCOTT, se mantiene un bloqueo
exclusivo sobre uno o más filas de la tabla HR.EMPLOYEES. Esta sesión no está
colgada – está operando normalmente. Pero la sesión numero 129, logueada como
usuario MPHO está bloqueada. Está esperando por un bloqueo Exclusivo sobre una
o más filas bloqueadas por la sesión 116. La sesión está colgada en este
momento y continuara colgada hasta que la sesión 116 libere el bloqueo
terminando la transacción con un COMMIT o un ROLLBACK. El segundo problema es
peor. JON está bloqueando dos sesiones, la de ISAAC y ROOP.
La contención de Bloqueo es una consecuencia
natural de muchos usuarios accediendo la misma información concurrentemente. El
problema puede ser exacerbado por un software mal diseñado, pero en principio
la contención de bloqueo es parte normal de la actividad de la base de datos. Por
lo tanto no es posible para el DBA resolverlo completamente – solo puede
identificar que es un problema, y sugerir a diseñadores de sistemas y
aplicaciones sobre la contención del bloqueo cuando diseñan.
Si los bloqueos se están convirtiendo en un
problema, como en la figura 10-5. Deben ser investigados. Database Control
proporciona la información necesaria. Haga doble clic en la columna “SQL ID” le
permitirá ver qué declaración está siendo ejecutada y es la que está causando
la contención de Bloqueo. En la figura,
SCOTT y MPHO ambos han ejecutado una declaración. JON, ISAAC y ROOP han
ejecutado otra. EL ROWID puede ser utilizado para buscar la fila exacta por la
cual las sesiones están en disputa. No se puede profundizar en la fila desde
esta ventana, pero el ROWID puede ser utilizado en una declaración SELECT para
recuperar la fila en otra sesión. Cuando el código y las filas que están
causando la contención son conocidos, una solución puede ser discutida con los
diseñadores de sistemas y desarrolladores.
En una emergencia, sin embargo, es posible
para el DBA para resolver el problema, terminar la sesión o sesiones que están
colgadas también por el bloqueo.
Cuando una sesión es terminada forzosamente,
cualquier bloqueo que posee serán liberados y la transacción activa será Roll
Back. Las sesiones bloqueadas se liberan y se puede continuar. Para terminar
una sesión, use el Database Control o el comando ALTER SYSTEM KILL SESSION. En
el ejemplo anterior, si usted decidió que la sesión SCOTT es la que mantiene el
bloqueo durante un periodo de tiempo absurdo. Debe seleccionar el botón de
radio para la sesión y clic el botón KILL SESSION. La transacción de HR serán
Roll Back y la sesión de MPHO entonces será capaz de tomar los bloqueos
requeridos y continuar trabajando. En caso del segundo problema en la figura,
matando la sesión de JOB libera a ISAAC que luego sería bloqueado por ROOP.
Dentro del
Examen.
Gestionando
Datos y Concurrencia.
En términos de los comandos mencionados en
este capítulo, hay una coincidencia enorme con el SQL y el programa de PL/SQL. Donde
el objeto es diferente es que este capitulo da detalles de cómo los comandos se
ejecutan: que sucede en disco, en disco y en el diccionario de datos cuando
varias sentencias DML y DDL se ejecutan.
Es vital tener una clara visión de los pasos a
seguir involucrados en la ejecución de sentencias SQL. La sentencia debe ser
primero generada por el proceso usuario. Luego enviada al proceso servidor. El proceso
servidor debe buscar la sentencia en la
Library Cache de la Shared Pool u analizarlas. Para ejecutar la sentencia, debe haber entrada y salida de Data Blocks. Si no
están en el Database Buffer Cache, el proceso servidor debe leer en la memoria
cache de los Datafiles. Si se trata de una sentencia SELECT, puede ser procesada en la PGA de la sesión. Si
es una sentencia DML, Change Vectors serán aplicados a los Block, pero primero
los Change Vectors serán escritos al Log Buffer, desde el cual son escritos a
los Onlne Redo Log Files en tiempo casi real (y es tiempo real para un commit).
La etapa final de la ejecución es regresar los resultados de la declaración de
nuevo al proceso usuario.
En muchos casos, las sentencias SQL serán
embebidas en bloques PL/SQL, estos bloques pueden estar almacenados o generados
en el lado del cliente (PL/SQL anónimo) o almacenados dentro de tablas del
diccionario de datos(PL/SQL almacenado).
El acceso a datos concurrentemente es gestionado a través del
mecanismo enqueue. Este es un medio por el cual sesiones bloquean filas que
serán afectadas por sentencias DML. Sesiones solicitan bloqueos sobre las
mismas filas en estas peticiones, colgándolas hasta que puedan obtener el
bloqueo. El mecanismo enqueue asegura que bloqueos son pasados en orden en que
fueron solicitados.
DeadLocks.
Es posible construir una posición donde dos
sesiones se bloquean en tal manera que ambas se cuelgen, cada una esperando a
la otra a liberar el bloqueo. Esto es un deadlock. Deadlock no son problema del
DBA. Son causandos por mal diseño de programas y resueltos automáticamente por
la Base de datos. Información relativa a deadlocks es escrita a los Alert Logs,
con detalle completo en un Trace File-parte de su monitoreo diario se recoge la
ocurrencia de los deadlocks e informar a sus desarrolladores que está
sucediendo.
Si un deadlock ocurren, ambas sesiones se
colgaran, pero solo por un breve momento. Una de las sesiones detectara el
Deadlocks en segundos, y hará un roll back a la sentencia que está causando el
problema. Esto liberara la otra sesión, regresando el mensaje “ORA-00060
Deadlock detected”. Este mensaje será atrapado por los programadores en sus
excepciones, que deben tomar las medidas adecuadas. Hay que destacar que
deadlocks son un fallo en el diseño del programa. Se producen debido a que el
código intenta hacer algo que es lógicamente imposible. Códigos bien escrito
siempre solicitan bloqueos en una secuencia que no puede causar bloqueos que se
produzcan, o pondrá a prueba si los bloqueos incompatibles ya existía antes de
que lo soliciten.
Examen.
Usted no puede hacer nada con deadlocks que se
reporten, serán resueltos automáticamente por la Base de Datos.
Ejercicio
10-3.
Detectar y
Resolver Contención de Bloqueo.
En este
ejercicio, usted primero utiliza SQLPLUS para causar un problema y
detectar y resolver con el Database Control.
1.Utilizando SQL*PLUS conéctese a su base de
datos en dos sesiones como usuario SYSTEM.
2.En la primera sesión, bloque todas las filas
en la tabla INTEGERS, que fue creada en el ejecicio 10-1.
select * from integers for update;
select * from integers for update;
3.En su segunda sesión, intente actualizar una
fila. La sesión de colgara.
update
integers set c2=’odder’ where c1=1;
4.Conéctese a su Database Control como usuario
SYSTEM.
5.Navegue a la ventana Instance Locks, por medio
de la pestaña Perfomance desde la pagina principal y luego Database Locks en la
sesión Monitoring.
6.Observe que la segunda sesión de SYSTEM
muestra que está en espera por un EXCLUSIVE Lock. Seleccione
el radio button para la primer Blocking Session y dar clic en Kill Session.
el radio button para la primer Blocking Session y dar clic en Kill Session.
7.En la ventana de confirmación, clic en mostrar
SQL. Mostrara un comando como este:
ALTER
SYSTEM KILL SESSION '120,1318' IMMEDIATE
8.Click en regresar y Yes para ejecutar el
commando KILL SESSION.
9.Regresar a su sesión SQL*PLUS, encontrara que
la segunda sesión está trabajando, pero la primera sesión no
puede ejecutar comandos.
puede ejecutar comandos.
10.Ordene el entorno:
Drop table integers;
Drop table integers;
Resumen de
Certificación.
Los comandos DML cambian datos. A medida que
se escriben data blocks en el database buffer cache, los change vectors
aplicados son escritos el Redo Log. Eventualmente, el DBWn escribe los buffers
cambiados a Disco. Sobreescribiendo la versión previa del Block, pero esto no
sucede en tiempo real. Por el contrario, los change vectors van a disco casi
inmediatamente. El método de procesamiento de COMMIT asegura que los datos
nunca se perderán, mediante la escritura de los change vectors en tiempo real
cuando un comando COMMIT es emitido. Un ROLLBACK es implementad mediante la
construcción de otra sentencia que revierta los efecos de todo el trabajo hecho
por la transacción. Los principios de aotmicidad, consistencia y aislamiento
son obligatorios el uso de segmentos Undo, que almacenan datos necesarios para
construir sentencias para reversar cambios. Cambios a los Segmentos Undo son
protegidos por el mecanismo Redo.
Bloques PL/SQL pueden ser enviados a
ejecución a la instancia como Bloques
anónimos enviados desde procesos usuarios o recuperados desde block almacenados
en el Diccionario de Daros. Estos bloques usualmente consisten de código
procedureal con SQL embebido.
Bloqueo de registro es completamente
automatico. El mecanismo por defecto asegura
el más alto nivel de
concurrencia: bloqueo a nivel de fila y no bloqueo para querys.
Dos
minutos.
Gestionando Datos utilizando DML.
·
Todos los comandos DML generan Undo y Redo.
·
Redo protege todos los cambios a segmentos –
Segmentos Undo, así como segmentos de Datos.
·
Procesos Servidor leen desde Data Files; DBWn escribe a Data Files.
Identificando y Administrando objetos PL/SQL.
·
PL/SQL anónimo es almacenado en el Cliente,
PL/SQL almacenado en el Diccionario de Datos.
·
Procedimientos y funciones pueden ser
empaquetados, triggers no pueden ser empaquetados.
·
Código PL/SQL puede llamar código SQL.
Monitorear y Resolver Conflictos de Bloqueo.
·
El nivel default de bloqueo es a nivel de fila.
·
Bloqueos son requeridos para todos los
comandos DML y son opcionales para SELECT.
·
Una declaración DML requiere bloqueo
compartido sobre el objeto involucrado y bloqueo exclusivo sobre la fila
involucrada.
·
Una DDL requiere bloqueo un bloqueo exclusivo sobre
el objeto afectado.
·
Deadlocks son resueltos automáticamente.
Gracias, excelente ayuda
ResponderEliminar