Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

cursor:pino S espera em X


No meu banco de dados RAC principal de produção, vejo períodos de lentidão e o evento de espera dominante, em todo o sistema, é “cursor:pin S wait on X”. O evento vem e vai, mas eu o vejo de vez em quando. Então eu precisava chegar ao fundo disso. Observe que isso não é um problema de RAC. Esse evento também pode ser visto facilmente em bancos de dados de instância única. Quando vejo isso em várias instâncias do meu banco de dados Oracle RAC, é porque tenho várias sessões do mesmo aplicativo espalhadas entre as instâncias, todas fazendo a mesma coisa, portanto, todas com o mesmo problema.

Primeiro, do que se trata o evento de espera? Qualquer uma das esperas de “cursor:” são gargalos no pool compartilhado na área SQL. Há muito tempo, essa parte do Shared Pool era protegida por travas. Mas como é o caso de muitas áreas do Shared Pool, a Oracle agora está usando mutexes. Com a mudança no mecanismo de proteção, agora temos novos eventos de espera.

No caso desse evento de espera específico, temos um cursor que deseja um pino compartilhado, mas precisa aguardar outra sessão liberar seu mutex exclusivo. Um cursor está tentando ser analisado. Mas não pode ser analisado porque outra sessão está segurando o mesmo mutex.

Existem três causas principais para as sessões em espera neste evento.
  • Análises difíceis altas
  • Um grande número de versões da instrução SQL
  • Erros

Infelizmente, há vários bugs relacionados a esse evento de espera. A maioria dos que eu vi são corrigidos em 11.2.0.4 ou 12.1.0.1, portanto, se você estiver atrasado nas versões, considere atualizar para uma das versões mais recentes do Oracle.

Então, vamos ver se podemos percorrer um exemplo para determinar a causa do problema. Para isso, usei a seguinte 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';



Executando isso em um dos meus bancos de dados RAC de produção, recebo a seguinte saída:
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

A primeira coisa a notar é que o mutex está apenas dentro dessa instância para bancos de dados Oracle RAC. Para bancos de dados de instância única, a consulta acima ainda funcionará. Para Oracle RAC, a saída dessa consulta mostrará qual instância está tendo o problema.

No exemplo acima, temos a sessão 723 bloqueada pela sessão 1226. A sessão 1226 também é bloqueada pela sessão 1796. Observe que todas as três sessões estão emitindo a mesma consulta com o ID SQL cn7m7t6y5h77g .

Agora que conhecemos o SQL ID, podemos facilmente consultar o V$SQL para determinar a instrução SQL envolvida no problema. Usei esta consulta para obter mais informações.
select sql_id,loaded_versions,executions,loads,invalidations,parse_calls
from gv$sql 
where inst_id=4 and sql_id='cn7m7t6y5h77g';

A saída da consulta V$SQL é a seguinte:
SQL_ID        LOADED_VERSIONS EXECUTIONS LOADS      INVALIDATIONS PARSE_CALLS
------------- --------------- ---------- ---------- ------------- -----------
cn7m7t6y5h77g               1        105        546           308        3513

Agora podemos ver que esta consulta possui apenas 1 versão na Área SQL. Então, imediatamente, eliminamos uma das possíveis áreas problemáticas. Em um post futuro no blog, discutirei consultas com alto número de versões na Área SQL. Mas esse não é o nosso problema hoje, então continuamos.

Deve ser óbvio a partir do exposto que há um número muito alto de chamadas de análise. A consulta foi executada apenas 105 vezes, mas foi analisada 3513 vezes. Caramba! O número alto de invalidação provavelmente tem algo a ver com isso também.

Neste exemplo, agora temos uma boa ideia de qual é o problema. Este é um problema de aplicativo. O aplicativo está analisando demais a consulta. Então, enviaremos isso de volta ao desenvolvimento e investigaremos o código do aplicativo. As razões usuais para análise excessiva precisam ser examinadas.

Se o número de versões fosse baixo e a análise/invalidações/cargas excessivas não fosse um problema, então eu suspeitaria de um bug e enviaria um SR ao Suporte da Oracle.