Skip to main content

Command Palette

Search for a command to run...

Cursor Sharing y Binds Grandes: Cómo Diagnosticamos y Solucionamos un Caso Real con el Evento 10503 en Oracle

Updated
4 min read
Cursor Sharing y Binds Grandes: Cómo Diagnosticamos y Solucionamos un Caso Real con el Evento 10503 en Oracle
C

Mi nombre es Carla y me defino como una apasionada de conocer, compartir ideas, divertirme y aprender todo lo relacionado con Oracle.

Alegre y creativa, con un alto grado de autoexigencia, que busca, incluso sin querer, una forma diferente de ver un mismo problema o solución. Defensora del trabajo en equipo en todas las facetas de la vida y de disfrutar todo lo que haces, siempre con humildad.

Actualmente cuento con más de 15 años de experiencia como administradora de Oracle, habiendo ocupado previamente posiciones como desarrolladora en la rama de Inteligencia de Negocios. Fue en ese momento que me di cuenta de que no quería centrarme en el desarrollo, sino participar en todas las capas que involucraban los datos, desde el despliegue de la base de datos hasta su explotación final.

Siempre estoy dispuesta a ayudar y compartir conocimientos. Creo firmemente que con la tecnología hay que divertirse y no verla como una competencia. La persona con la que tienes que ser el mejor es contigo mismo.

En entornos Oracle de alto rendimiento, la aparición de múltiples child cursors debido a BIND_MISMATCH es un problema común que puede degradar el rendimiento significativamente.

Nuestra aplicación, que utiliza extended strings, comenzó a presentar una elevada cantidad de child cursors en dos sentencias INSERT críticas.

La Investigación y el Diagnóstico

El primer paso fue identificar el origen exacto del BIND_MISMATCH. Para ello, seguimos un proceso meticuloso:

Identificación de los SQL_ID problemáticos: A través de V$SQL y V$SQL_SHARED_CURSOR, localizamos los dos SQL_ID involucrados (xxxxxxxxxxxxx1 y xxxxxxxxxxxxx2).

Para encontrar el motivo de un cursor no compartido:

-- Script Code
set serveroutput on

DECLARE
  v_count number;
  v_sql varchar2(500);
  v_sql_id varchar2(30) := '&sql_id';
BEGIN
  v_sql_id := lower(v_sql_id);
  dbms_output.put_line(chr(13)||chr(10));
  dbms_output.put_line('sql_id: '||v_sql_id);
  dbms_output.put_line('------------------------');
  FOR c1 in
    (select column_name 
       from dba_tab_columns
      where table_name ='V_$SQL_SHARED_CURSOR'
        and column_name not in ('SQL_ID', 'ADDRESS', 'CHILD_ADDRESS', 'CHILD_NUMBER', 'REASON', 'CON_ID')
      order by column_id)
  LOOP
    v_sql := 'select count(*) from V_$SQL_SHARED_CURSOR
              where sql_id='||''''||v_sql_id||''''||'
              and '||c1.column_name||'='||''''||'Y'||'''';
    execute immediate v_sql into v_count;
    IF v_count > 0
    THEN
      dbms_output.put_line(' - '||rpad(c1.column_name,30)||' count: '||v_count);
    END IF;
  END LOOP;
END;

Versions Summary
----------------
BIND_MISMATCH :121 <<<<<<<<<<-----------------
ROLL_INVALID_MISMATCH :2
BIND_LENGTH_UPGRADEABLE :9

Análisis de los binds: La clave fue consultar la vista V$SQL_BIND_CAPTURE para entender la variabilidad en el tamaño de los binds para cada una de las sentencias.

Para el primer SQL_ID: sql

SELECT COUNT(*) AS count,
       position,
       MIN(max_length) AS min_length,
       MAX(max_length) AS max_length,
       datatype,
       CASE 
         WHEN MAX(value_string) IS NOT NULL THEN 'Yes' 
         ELSE 'No' 
       END AS bind_captured,
       '('||MAX(precision)||','||MAX(scale)||')' AS graduation
  FROM gv$sql_bind_capture
  WHERE  sql_id = 'xxxxxxxxxxxxx1'
 GROUP BY position, datatype
 ORDER BY max_length desc;

COUNT(*) POSITION MIN(MAX_LENGTH) MAX(MAX_LENGTH) DATATYPE BIND GRADUATION (PRECISION,SCALE)
======== ======== =============== =============== ======== =============== =================
21 1 22 22 2 No (,)
21 2 32 32 1 No (,)
21 3 2000 2000 1 No (,)
21 4 2000 2000 1 No (,)
21 5 2000 2000 1 No (,)
21 6 7 7 12 No (,)
21 7 22 22 2 No (,)
12 8 2000 2000 1 No (,)
9 8 22 22 2 No (,)
21 9 32 2000 1 Yes (,)
21 10 128 128 1 No (,)
21 11 128 128 1 No (,)
21 12 22 22 2 No (,)
21 13 2000 2000 1 No (,)
21 14 2000 2000 1 No (,)
21 15 32 2000 1 Yes (,)
21 16 2000 2000 1 No (,)
21 17 128 2000 1 Yes (,)

Los resultados mostraron que los binds de tipo VARCHAR2 en varias posiciones variaban entre 32 y 2000 bytes. ¡Este era el culpable del BIND_MISMATCH para la primera INSERT.

High Version Count Due To BIND_MISMATCH ( Doc ID 336268.1 )

Aplicación de la solución: Basándonos en este análisis, aplicamos el evento 10503 con el nivel específico que necesitábamos:

ALTER SYSTEM SET EVENTS '10503 trace name context forever, level 2000';

Resultado: El problema de los child cursors para la primera sentencia INSERT se resolvió por completo.

El segundo problema: Tras el primer éxito, nos enfocamos en el segundo SQL_ID (xxxxxxxxxxxxx2). Repetimos el análisis y descubrimos que sus binds llegaban hasta 16,386 bytes.

Aplicamos el evento con un nivel superior:

ALTER SYSTEM SET EVENTS '10503 trace name context forever, level 16386';

La Limitación

Para nuestra sorpresa, el segundo problema no se resolvió. Al contactar con Soporte de Oracle, confirmaron nuestra sospecha: el evento 10503 tiene una limitación interna y no funciona para binds mayores a 4000 bytes, incluso si se establece un nivel superior.

Conclusión y Lecciones Aprendidas

El diagnóstico es clave: La solución no es aplicar el evento 10503 a ciegas. La consulta a V$SQL_BIND_CAPTURE para obtener el MAX(MAX_LENGTH) de los binds problemáticos es un paso fundamental y no negociable para determinar el nivel correcto.

Solución para binds <= 4000 bytes: Para la primera INSERT, el evento 10503 configurado al nivel preciso (2000) fue la solución perfecta y eliminó el BIND_MISMATCH.

Limitación actual para binds > 4000 bytes: Para la segunda INSERT, chocamos con un muro. Oracle confirmó que no hay solución nativa actualmente y que no hay planes a corto plazo para extender el evento más allá de 4000 bytes.

Reflexión Final

Este caso es un ejemplo perfecto de cómo un enfoque metódico—identificar, diagnosticar y aplicar—nos permitió resolver el 50% del problema. Para el otro 50%, nos topamos con una limitación actual de la base de datos.

Cambio persistente en spfile

Para que el cambio aplique tras reinicios

ALTER SYSTEM SET EVENT= '10503 trace name context forever, level 2000'  COMMENT='High Version Count Due To BIND_MISMATCH' SCOPE=SPFILE SID='*';

More from this blog

Carla Muñoz López

64 posts

Soy DBA senior de bases de datos Oracle y me defino como una persona alegre y creativa. Apasionada por conocer, compartir ideas, divertirme y seguir aprendiendo todo lo relacionado con Oracle.