På min huvudsakliga produktions-RAC-databas ser jag perioder av långsamhet och den dominerande väntehändelsen, hela systemet, är "markör:stift S vänta på X". Händelsen kommer och går, men jag ser den då och då. Så jag behövde komma till botten med det här. Observera att detta inte är ett RAC-problem. Denna händelse kan också enkelt ses i databaser med en instans. När jag ser detta på flera instanser av min Oracle RAC-databas beror det på att jag har flera sessioner från samma applikation utspridda bland instanserna, alla gör samma sak, och därför har alla samma problem.
För det första, vad handlar väntandet om? Vilken som helst av "cursor:"-väntningarna är flaskhalsar i den delade poolen i SQL-området. För länge sedan var denna del av den delade poolen skyddad av spärrar. Men som är fallet med många delar av den delade poolen, använder Oracle nu mutexes. Med förändringen av skyddsmekanismen har vi nu nya väntehändelser.
I fallet med just den här väntande händelsen har vi en markör som vill ha en delad pin men som måste vänta på en annan session för att släppa dess exklusiva mutex. En markör försöker tolkas. Men det kan inte tolkas eftersom en annan session håller fast vid samma mutex.
Det finns tre huvudorsaker till att sessioner väntar på denna händelse.
- Höga hårdanalyser
- Ett stort antal versioner av SQL-satsen
- Buggar
Tyvärr finns det ett antal buggar relaterade till denna väntande händelse. De flesta av de som jag har sett är fixade i 11.2.0.4 eller 12.1.0.1, så om du släpar efter i versioner, överväg att uppgradera till en av de nyare Oracle-versionerna.
Så låt oss se om vi kan gå igenom ett exempel för att fastställa orsaken till problemet. För att göra det använde jag följande fråga:
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 jag kör detta i en av mina produktions-RAC-databaser får jag följande utdata:
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
Det första att notera är att mutex endast finns inom den instansen för Oracle RAC-databaser. För eninstansdatabaser fungerar frågan ovan fortfarande. För Oracle RAC kommer utdata från denna fråga att visa vilken instans som har problemet.
I exemplet ovan har vi session 723 blockerad av session 1226. Session 1226 blockeras ytterligare av session 1796. Observera att alla tre sessioner utfärdar samma fråga med SQL ID cn7m7t6y5h77g .
Nu när vi känner till SQL-ID:t kan vi enkelt fråga V$SQL för att fastställa vilken SQL-sats som är involverad i problemet. Jag använde den här frågan för att få mer information.
select sql_id,loaded_versions,executions,loads,invalidations,parse_calls from gv$sql where inst_id=4 and sql_id='cn7m7t6y5h77g';
Utdata från att fråga V$SQL är som följer:
SQL_ID LOADED_VERSIONS EXECUTIONS LOADS INVALIDATIONS PARSE_CALLS ------------- --------------- ---------- ---------- ------------- ----------- cn7m7t6y5h77g 1 105 546 308 3513
Vi kan nu se att denna fråga bara har en version i SQL-området. Så direkt har vi eliminerat ett av de potentiella problemområdena. I ett framtida blogginlägg kommer jag att diskutera frågor med ett stort antal versioner i SQL-området. Men det är inte vårt problem idag så vi fortsätter.
Det borde vara uppenbart av ovanstående att det finns ett mycket stort antal parse-anrop. Frågan har bara körts 105 gånger men har analyserats 3513 gånger. Hoppsan! Den höga siffran om ogiltigförklaring har förmodligen också med detta att göra.
I det här exemplet har vi nu en bra uppfattning om vad problemet är. Detta är en applikationsfråga. Applikationen överparsar frågan. Så vi skickar tillbaka detta till utveckling och gräver i applikationskoden. De vanliga orsakerna till överparsning måste undersökas.
Om antalet versioner var lågt och överdriven analys/ogiltigförklaring/laddning inte var ett problem, skulle jag misstänka en bugg och lämna in en SR med Oracle Support.