miércoles, 14 de marzo de 2012

Problema de bloqueos TM - Contention en Oracle Database 11gR2

En estos ya 15 días después de haber realizado la migración, han salido varios problemas que en la etapa de pruebas no fueron detectadas, una de ellas es que de pronto un simple DML (por ejemplo un INSERT) bloqueaba toda una tabla no permitiendo que otros usuarios tuvieran acceso ni con un SELECT a los registros.

Después de buscar un rato (resolviendo el problema mediante la muerte de la sesión del usuario problemático), la investigación me llevo a esta página http://www.confio.com/blog/solving-waits-on-enq-tm-contention , en la cual describen que para la versión 11g, si las FK's de una tabla no están indexadas, al insertar un valor bloquea todo el objeto y objetos relacionados.

La solución, como pueden deducir, es crear los índices, basado en ello construí este SQL que me permite obtener las instrucciones DDL para crearlos. Es necesario decir que ya con las sentencias me puse a revisar una a una para ver a que tablespace la debía dirigir ya que me heredaron una BD no muy organizada (esa es oooootro de mis proyectos, la reestructuración) y tenía que asignarlos a donde estaban los demás. En el caso de ustedes, si quieren evitarse esa talacha pueden hacer un tablespace nuevo para esos indices y ahí dirigirlos.


-- Solución a TM - Contention (Bloqueos masivos de tablas)
-- Indican en la página que al realizar un INSERT en una tabla con FK's
-- se hace un bloqueo completo de la tabla si estas columnas no están indexadas
-- Este script obtiene las columnas con FK pero que no están indexadas, dandonos
-- la sentencia con el SQL a ejecutar para crearlo
SELECT 'CREATE INDEX '||column_name||'_FK ON '||owner||'.'||table_name||'('||column_name||');'
FROM (
        SELECT c.owner owner, c.table_name table_name, cc.column_name, cc.position column_position
        FROM   dba_constraints c, dba_cons_columns cc
        WHERE  c.constraint_name = cc.constraint_name
        AND    c.constraint_type = 'R'
        and    c.owner='OWNER'
        MINUS
        SELECT i.owner, i.table_name, ic.column_name, ic.column_position
        FROM   dba_indexes i, dba_ind_columns ic
        WHERE  i.index_name = ic.index_name
        AND i.owner='OWNER'
)
ORDER BY table_name, column_position;


Ya con los índices creados, notarán que los bloqueos dejan de ser TM - EXCLUSIVE y pasan a TM - ROW EXCLUSIVE con su respectivo TX.

Se han realizado más modificaciones, y todas las iré incluyendo en este blog.

Actualización:

Esta situación ocurre con clientes no soportados según la matriz de certificación de Oracle, en mi caso el problema se presenta con clientes de la versión 8i. Ya que traté de reproducir el mismo error con clientes 10g - 11g y no se presentaron esos bloqueos aún cuando no se habían creado los índices para las llaves foráneas.

Otro tema es que si las FK corresponden a llaves combinadas, los índices deben crearse también combinados, esta consideración no se resuelve en la consulta mostrada anteriormente, por lo que en mi caso, tuve que realizarla manualmente en las tablas que seguían presentando el caso.

6 comentarios:

  1. no me ha funcionado¡

    ResponderEliminar
  2. Puedes explicarme tu caso para apoyarte en su solución, seguramente hay algún otro problema...

    ResponderEliminar
  3. "Esta situación ocurre con clientes no soportados según la matriz de certificación de Oracle, en mi caso el problema se presenta con clientes de la versión 8i."
    ¿Está verificado de otra fuente o hablas de tu experiencia?

    Yo estoy tanteando un problema similar, y lo mismo, estoy tratando de reproducir el problema pero no hay forma. Ahora, leyendo lo que dices de que sólo sucede con clientes no soportados arroja algo de luz, por que donde nos estaba sucediendo ésto algunos clientes eran versión 9i... sin embargo esos eran los que se quedaban bloqueados. El bloqueador era un cliente 11.

    ResponderEliminar
    Respuestas
    1. Lo verifiqué en un curso de administración de Base de Datos Oracle, así mismo pude reproducir el error en mi trabajo y nunca pude hacerlo con clientes 10 u 11.

      Sobre lo que mencionas que el bloqueador era un cliente 11g y tomando en cuenta lo que menciono en el post deduzco lo siguiente: el cliente 11 solo bloquea un registro, las operaciones de los clientes 9i quieren "apartar" toda la tabla y como un registro no lo pueden apartar, ahí tienes el problema. Eso si, ese bloqueo debe desaparecer al momento de hacer commit con el cliente 11g.

      Trata de reproducir otros casos y me comentas que resultados tienes.

      Saludos!

      Eliminar
  4. Buen Aporte Roger.. tenes mas pruebas de bloqueos?

    ResponderEliminar

Deja tu comentario aquí