En mi base de datos RAC de producción principal, veo períodos de lentitud y el evento de espera dominante, en todo el sistema, es "cursor:pin S espera en X". El evento va y viene, pero lo veo de vez en cuando. Así que necesitaba llegar al fondo de esto. Tenga en cuenta que esto no es un problema de RAC. Este evento también se puede ver fácilmente en bases de datos de instancia única. Cuando veo esto en varias instancias de mi base de datos Oracle RAC, es porque tengo varias sesiones de la misma aplicación repartidas entre las instancias, todas haciendo lo mismo, por lo que todas tienen el mismo problema.
Primero, ¿de qué se trata el evento de espera? Cualquiera de las esperas de "cursor:" son cuellos de botella en el grupo compartido en el área SQL. Hace mucho tiempo, esta parte de la Piscina Compartida estaba protegida por cerrojos. Pero como es el caso con muchas áreas del Shared Pool, Oracle ahora usa mutexes. Con el cambio en el mecanismo de protección, ahora tenemos nuevos eventos de espera.
En el caso de este evento de espera en particular, tenemos un cursor que quiere un PIN compartido pero debe esperar a que otra sesión libere su mutex exclusivo. Un cursor está tratando de ser analizado. Pero no se puede analizar porque otra sesión se aferra al mismo mutex.
Hay tres causas principales para las sesiones en espera de este evento.
- Análisis muy duros
- Un gran número de versiones de la instrucción SQL
- Errores
Desafortunadamente, hay una serie de errores relacionados con este evento de espera. La mayoría de los que he visto están corregidos en 11.2.0.4 o 12.1.0.1, por lo que si se está quedando atrás en las versiones, considere actualizar a una de las versiones más recientes de Oracle.
Entonces, veamos si podemos analizar un ejemplo para determinar la causa del problema. Para ello, utilicé la siguiente consulta:
select s.inst_id as inst, s.sid as blocked_sid, s.username as blocked_user, sa.sql_id as blocked_sql_id, trunc(s.p2/4294967296) as blocking_sid, b.username as blocking_user, b.sql_id as blocking_sql_id from gv$session s join gv$sqlarea sa on sa.hash_value = s.p1 join gv$session b on trunc(s.p2/4294967296)=b.sid and s.inst_id=b.inst_id join gv$sqlarea sa2 on b.sql_id=sa2.sql_id where s.event='cursor: pin S wait on X';
Al ejecutar esto en una de mis bases de datos RAC de producción, obtengo el siguiente resultado:
INST BLOCKED_SID BLOCKED_USER BLOCKED_SQL_ID BLOCKING_SID BLOCKING_USER BLOCKING_SQL_ID ---- ----------- ------------ -------------- ------------ ------------- --------------- 4 723 USER12345 cn7m7t6y5h77g 1226 USER12345 cn7m7t6y5h77g 4 723 USER12345 cn7m7t6y5h77g 1226 USER12345 cn7m7t6y5h77g 4 723 USER12345 cn7m7t6y5h77g 1226 USER12345 cn7m7t6y5h77g 4 723 USER12345 cn7m7t6y5h77g 1226 USER12345 cn7m7t6y5h77g 4 1226 USER12345 cn7m7t6y5h77g 1796 USER12345 cn7m7t6y5h77g 4 1226 USER12345 cn7m7t6y5h77g 1796 USER12345 cn7m7t6y5h77g 4 1226 USER12345 cn7m7t6y5h77g 1796 USER12345 cn7m7t6y5h77g 4 1226 USER12345 cn7m7t6y5h77g 1796 USER12345 cn7m7t6y5h77g
Lo primero que debe tener en cuenta es que el mutex solo está dentro de esa instancia para las bases de datos Oracle RAC. Para las bases de datos de instancia única, la consulta anterior seguirá funcionando. Para Oracle RAC, el resultado de esta consulta mostrará qué instancia tiene el problema.
En el ejemplo anterior, tenemos la sesión 723 bloqueada por la sesión 1226. La sesión 1226 está bloqueada aún más por la sesión 1796. Observe que las tres sesiones emiten la misma consulta con el ID de SQL cn7m7t6y5h77g .
Ahora que conocemos el ID de SQL, podemos consultar fácilmente V$SQL para determinar la instrucción SQL involucrada en el problema. Utilicé esta consulta para obtener más información.
select sql_id,loaded_versions,executions,loads,invalidations,parse_calls from gv$sql where inst_id=4 and sql_id='cn7m7t6y5h77g';
El resultado de consultar V$SQL es el siguiente:
SQL_ID LOADED_VERSIONS EXECUTIONS LOADS INVALIDATIONS PARSE_CALLS ------------- --------------- ---------- ---------- ------------- ----------- cn7m7t6y5h77g 1 105 546 308 3513
Ahora podemos ver que esta consulta tiene solo 1 versión en el Área SQL. De inmediato, hemos eliminado una de las posibles áreas problemáticas. En una publicación de blog futura, analizaré las consultas con una gran cantidad de versiones en el área de SQL. Pero ese no es nuestro problema hoy, así que procedemos.
Debería ser obvio por lo anterior que hay un número muy alto de llamadas de análisis. La consulta solo se ejecutó 105 veces, pero se analizó 3513 veces. ¡Ay! El alto número de invalidaciones probablemente también tenga algo que ver con esto.
En este ejemplo, ahora tenemos una buena idea de cuál es el problema. Este es un problema de aplicación. La aplicación está analizando en exceso la consulta. Así que enviaremos esto de vuelta a desarrollo y profundizaremos en el código de la aplicación. Es necesario examinar las razones habituales del análisis excesivo.
Si el número de versiones fuera bajo y el análisis/invalidaciones/cargas excesivas no fuera un problema, entonces sospecharía un error y presentaría una SR con Oracle Support.