sql >> Database >  >> RDS >> Oracle

cursor:pin S wacht op X

In mijn belangrijkste productie-RAC-database zie ik perioden van traagheid en de dominante wachtgebeurtenis, systeembreed, is "cursor:pin S wacht op X". Het evenement komt en gaat, maar ik zie het van tijd tot tijd. Ik moest dit dus tot op de bodem uitzoeken. Merk op dat dit geen RAC-probleem is. Deze gebeurtenis is ook gemakkelijk te zien in databases met één instantie. Als ik dit op meerdere instanties van mijn Oracle RAC-database zie, komt dat omdat ik meerdere sessies van dezelfde applicatie heb verspreid over de instanties, die allemaal hetzelfde doen en dus allemaal hetzelfde probleem hebben.

Ten eerste, waar gaat het wachtevenement over? Elk van de "cursor:"-wachten zijn knelpunten in de gedeelde pool in het SQL-gebied. Lang geleden was dit gedeelte van de Shared Pool beveiligd met vergrendelingen. Maar zoals het geval is met veel delen van de Shared Pool, gebruikt Oracle nu mutexen. Met de wijziging in het beschermingsmechanisme hebben we nu nieuwe wachtgebeurtenissen.

In het geval van deze specifieke wachtgebeurtenis hebben we een cursor die een gedeelde pin wil, maar moet wachten op een andere sessie om zijn eXclusive mutex vrij te geven. Een cursor probeert te worden geparseerd. Maar het kan niet worden geparseerd omdat een andere sessie dezelfde mutex vasthoudt.

Er zijn drie hoofdoorzaken voor het wachten op sessies op dit evenement.

  • Hoge harde parsen
  • Een groot aantal versies van de SQL-instructie
  • Bug

Helaas zijn er een aantal bugs gerelateerd aan deze wachtgebeurtenis. De meeste die ik heb gezien, zijn opgelost in 11.2.0.4 of 12.1.0.1, dus als je achterloopt in versies, overweeg dan om te upgraden naar een van de recentere Oracle-versies.

Laten we dus eens kijken of we een voorbeeld kunnen doorlopen om de oorzaak van het probleem te achterhalen. Om dat te doen, heb ik de volgende query gebruikt:

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

Als ik dit in een van mijn productie-RAC-databases uitvoer, krijg ik de volgende uitvoer:

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

Het eerste dat moet worden opgemerkt, is dat de mutex zich alleen binnen die instantie bevindt voor Oracle RAC-databases. Voor databases met één instantie werkt de bovenstaande query nog steeds. Voor Oracle RAC zal de uitvoer van deze query laten zien welke instantie het probleem heeft.

In het bovenstaande voorbeeld hebben we sessie 723 geblokkeerd door sessie 1226. Sessie 1226 wordt verder geblokkeerd door sessie 1796. Merk op dat alle drie de sessies dezelfde query uitvoeren met SQL-ID cn7m7t6y5h77g .

Nu we de SQL-ID kennen, kunnen we V$SQL eenvoudig opvragen om de SQL-instructie te bepalen die bij het probleem betrokken is. Ik heb deze zoekopdracht gebruikt om meer informatie te verkrijgen.

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

De uitvoer van het opvragen van V$SQL is als volgt:

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

We kunnen nu zien dat deze query slechts 1 versie heeft in het SQL-gebied. We hebben dus meteen een van de potentiële probleemgebieden geëlimineerd. In een toekomstige blogpost zal ik vragen bespreken met een groot aantal versies in het SQL-gebied. Maar dat is niet ons probleem vandaag, dus we gaan verder.

Uit het bovenstaande mag duidelijk zijn dat er een zeer hoog aantal parse-aanroepen is. De query is slechts 105 keer uitgevoerd, maar is 3513 keer geparseerd. Jakkes! Het hoge aantal als ongeldigverklaring heeft hier waarschijnlijk ook iets mee te maken.

In dit voorbeeld hebben we nu een goed idee van wat het probleem is. Dit is een toepassingsprobleem. De toepassing over-parseert de query. Dus we sturen dit terug naar ontwikkeling en graven in de applicatiecode. De gebruikelijke redenen voor over-parsing moeten worden onderzocht.

Als het aantal versies laag was en overmatig parseren/invalideren/laden geen probleem was, zou ik een bug vermoeden en een SR indienen bij Oracle Support.


  1. Functie om een ​​dynamische set kolommen voor een bepaalde tabel te retourneren

  2. Hoe LOG2() werkt in MariaDB

  3. Hoe gebruik ik CREATE OR REPLACE?

  4. Mysql:selecteer rijen uit een tabel die niet in een andere staan