Oracle
 sql >> Base de données >  >> RDS >> Oracle

curseur :broche S attendre sur X

Sur ma base de données RAC de production principale, je vois des périodes de lenteur et l'événement d'attente dominant, à l'échelle du système, est "curseur :broche S en attente sur X". L'événement va et vient, mais je le vois de temps en temps. J'avais donc besoin d'aller au fond des choses. Notez qu'il ne s'agit pas d'un problème de RAC. Cet événement est également facilement visible sur les bases de données à instance unique. Lorsque je vois cela sur plusieurs instances de ma base de données Oracle RAC, c'est parce que j'ai plusieurs sessions de la même application réparties entre les instances, faisant toutes la même chose, donc toutes ayant le même problème.

Tout d'abord, en quoi consiste l'événement d'attente ? Toutes les attentes du "curseur :" sont des goulots d'étranglement dans le pool partagé de la zone SQL. Il y a longtemps, cette partie de la piscine partagée était protégée par des loquets. Mais comme c'est le cas avec de nombreuses zones du pool partagé, Oracle utilise désormais des mutex. Avec la modification du mécanisme de protection, nous avons maintenant de nouveaux événements d'attente.

Dans le cas de cet événement d'attente particulier, nous avons un curseur qui veut une épingle partagée, mais qui doit attendre qu'une autre session libère son mutex exclusif. Un curseur essaie d'être analysé. Mais il ne peut pas être analysé car une autre session conserve le même mutex.

Il existe trois causes principales pour les sessions en attente de cet événement.

  • Analyses difficiles élevées
  • Un grand nombre de versions de l'instruction SQL
  • Bogues

Malheureusement, il existe un certain nombre de bogues liés à cet événement d'attente. La plupart de ceux que j'ai vus sont corrigés dans 11.2.0.4 ou 12.1.0.1, donc si vous êtes à la traîne dans les versions, envisagez de passer à l'une des versions Oracle les plus récentes.

Voyons donc si nous pouvons parcourir un exemple pour déterminer la cause du problème. Pour ce faire, j'ai utilisé la requête suivante :

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';

En exécutant ceci dans l'une de mes bases de données RAC de production, j'obtiens le résultat suivant :

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

La première chose à noter est que le mutex se trouve uniquement dans cette instance pour les bases de données Oracle RAC. Pour les bases de données à instance unique, la requête ci-dessus fonctionnera toujours. Pour Oracle RAC, la sortie de cette requête indiquera quelle instance rencontre le problème.

Dans l'exemple ci-dessus, nous avons la session 723 bloquée par la session 1226. La session 1226 est encore bloquée par la session 1796. Notez que les trois sessions émettent la même requête avec l'ID SQL cn7m7t6y5h77g .

Maintenant que nous connaissons l'ID SQL, nous pouvons facilement interroger V$SQL pour déterminer l'instruction SQL impliquée dans le problème. J'ai utilisé cette requête pour obtenir plus d'informations.

select sql_id,loaded_versions,executions,loads,invalidations,parse_calls
from gv$sql 
where inst_id=4 and sql_id='cn7m7t6y5h77g';

Le résultat de l'interrogation de V$SQL est le suivant :

SQL_ID        LOADED_VERSIONS EXECUTIONS LOADS      INVALIDATIONS PARSE_CALLS
------------- --------------- ---------- ---------- ------------- -----------
cn7m7t6y5h77g               1        105        546           308        3513

Nous pouvons maintenant voir que cette requête n'a qu'une seule version dans la zone SQL. Donc, tout de suite, nous avons éliminé l'un des problèmes potentiels. Dans un futur article de blog, je discuterai des requêtes avec un nombre élevé de versions dans la zone SQL. Mais ce n'est pas notre problème aujourd'hui, alors nous continuons.

Il devrait être évident d'après ce qui précède qu'il y a un nombre très élevé d'appels d'analyse. La requête n'a été exécutée que 105 fois mais a été analysée 3513 fois. Aïe ! Le nombre élevé d'invalidations a probablement aussi quelque chose à voir avec cela.

Dans cet exemple, nous avons maintenant une bonne idée du problème. Il s'agit d'un problème d'application. L'application suranalyse la requête. Nous allons donc renvoyer cela au développement et creuser dans le code de l'application. Les raisons habituelles de suranalyse doivent être examinées.

Si le nombre de versions était faible et que l'analyse/les invalidations/les chargements excessifs n'étaient pas un problème, alors je suspecterais un bogue et déposerais une SR auprès du support Oracle.