miércoles, 4 de julio de 2012

10.3. MONITOREAR Y RESOLVER CONFLICTOS DE BLOQUEOS.

MONITOREAR Y RESOLVER CONFLICTOS DE BLOQUEOS.
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;
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.
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.
10.Ordene el entorno:
   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.


1 comentario: