sql >> Database teknologi >  >> RDS >> Oracle

markør:pin S vent på X

På min primære produktions-RAC-database ser jeg perioder med langsommelighed, og den dominerende ventehændelse, hele systemet, er "markør:pin S vent på X". Arrangementet kommer og går, men jeg ser det fra tid til anden. Så jeg var nødt til at finde bunden af ​​det her. Bemærk, at dette ikke er et RAC-problem. Denne hændelse kan også nemt ses på enkeltforekomstdatabaser. Når jeg ser dette på flere forekomster af min Oracle RAC-database, skyldes det, at jeg har flere sessioner fra den samme applikation spredt ud blandt forekomsterne, som alle gør det samme, og derfor har alle det samme problem.

For det første, hvad handler ventebegivenheden om? Enhver af "cursor:"-venterne er flaskehalse i den delte pool i SQL-området. For lang tid siden var denne del af den fælles pool beskyttet af låse. Men som det er tilfældet med mange områder af den delte pool, bruger Oracle nu mutexes. Med ændringen i beskyttelsesmekanismen har vi nu nye ventebegivenheder.

I tilfælde af denne særlige ventehændelse har vi en markør, der ønsker en delt pin, men som skal vente på en anden session for at frigive dens eksklusive mutex. En markør forsøger at blive analyseret. Men det kan ikke parses, fordi en anden session holder på den samme mutex.

Der er tre hovedårsager til sessioner, der venter på denne begivenhed.

  • Høj hårde parses
  • Et stort antal versioner af SQL-sætningen
  • Bugs

Desværre er der en række fejl relateret til denne ventebegivenhed. De fleste af dem, jeg har set, er rettet i 11.2.0.4 eller 12.1.0.1, så hvis du halter bagud i versioner, kan du overveje at opgradere til en af ​​de nyere Oracle-versioner.

Så lad os se, om vi kan gennemgå et eksempel for at bestemme årsagen til problemet. For at gøre det brugte jeg følgende forespørgsel:

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

Når jeg kører dette i en af ​​mine produktions-RAC-databaser, får jeg følgende output:

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

Den første ting at bemærke er, at mutex kun er inden for denne instans for Oracle RAC-databaser. For enkeltforekomstdatabaser vil forespørgslen ovenfor stadig fungere. For Oracle RAC vil outputtet fra denne forespørgsel vise, hvilken instans der har problemet.

I eksemplet ovenfor har vi session 723 blokeret af session 1226. Session 1226 er yderligere blokeret af session 1796. Bemærk, at alle tre sessioner udsender den samme forespørgsel med SQL ID cn7m7t6y5h77g .

Nu hvor vi kender SQL ID'et, kan vi nemt forespørge V$SQL for at bestemme SQL-sætningen involveret i problemet. Jeg brugte denne forespørgsel til at få flere oplysninger.

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

Outputtet fra at forespørge V$SQL er som følger:

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

Vi kan nu se, at denne forespørgsel kun har 1 version i SQL-området. Så med det samme har vi elimineret et af de potentielle problemområder. I et fremtidigt blogindlæg vil jeg diskutere forespørgsler med et stort antal versioner i SQL-området. Men det er ikke vores problem i dag, så vi fortsætter.

Det burde være tydeligt ud fra ovenstående, at der er et meget højt antal parse-kald. Forespørgslen er kun blevet udført 105 gange, men er blevet parset 3513 gange. Yikes! Det høje tal, hvis invalidering er, har sandsynligvis også noget at gøre med dette.

I dette eksempel har vi nu en god idé om, hvad problemet er. Dette er et applikationsproblem. Applikationen overparser forespørgslen. Så vi sender dette tilbage til udvikling og graver i applikationskoden. De sædvanlige årsager til overparsing skal undersøges.

Hvis antallet af versioner var lavt, og overdreven parsing/ugyldiggørelser/indlæsninger ikke var et problem, ville jeg mistænke en fejl og indsende en SR til Oracle Support.


  1. Den nemmeste måde at lave en rekursiv selv-join på?

  2. SQL Server 2016:OLTP-forbedringer i hukommelsen

  3. SQL:Parse kommasepareret streng og brug som join

  4. Hvad gør ::i PostgreSQL?