sql >> Databáze >  >> RDS >> Oracle

kurzor:pin S počkejte na X

V mé hlavní produkční databázi RAC vidím období zpomalení a dominantní událost čekání v celém systému je „kurzor:pin S čekání na X“. Událost přichází a odchází, ale čas od času ji vidím. Takže jsem tomu potřeboval přijít na kloub. Upozorňujeme, že se nejedná o problém RAC. Tuto událost lze snadno vidět i na jednoinstančních databázích. Když to vidím na více instancích své databáze Oracle RAC, je to proto, že mám několik relací ze stejné aplikace rozprostřených mezi instancemi, všechny dělají totéž, takže všechny mají stejný problém.

Za prvé, o čem je událost čekání? Jakékoli čekání na „kurzor:“ jsou úzká hrdla ve sdíleném fondu v oblasti SQL. Před dlouhou dobou byla tato část sdíleného fondu chráněna západkami. Ale jak je tomu v mnoha oblastech sdíleného fondu, Oracle nyní používá mutexy. Se změnou mechanismu ochrany nyní máme nové události čekání.

V případě této konkrétní události čekání máme kurzor, který požaduje sdílený PIN, ale musí čekat na další relaci, aby uvolnil svůj exkluzivní mutex. Kurzor se pokouší analyzovat. Nelze jej však analyzovat, protože na stejném mutexu se drží jiná relace.

Existují tři hlavní příčiny relací čekajících na tuto událost.

  • Vysoce náročné analýzy
  • Velký počet verzí příkazu SQL
  • Chyby

Bohužel s touto událostí čekání souvisí řada chyb. Většina z těch, které jsem viděl, je opravena v 11.2.0.4 nebo 12.1.0.1, takže pokud zaostáváte ve verzích, zvažte upgrade na jednu z novějších verzí Oracle.

Pojďme se tedy podívat, zda můžeme projít příkladem, abychom určili příčinu problému. K tomu jsem použil následující dotaz:

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

Když to spustím v jedné z mých produkčních databází RAC, dostanu následující výstup:

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

První věc, kterou je třeba poznamenat, je, že mutex je pouze v rámci této instance pro databáze Oracle RAC. U jednoinstančních databází bude výše uvedený dotaz stále fungovat. Pro Oracle RAC výstup z tohoto dotazu ukáže, která instance má problém.

Ve výše uvedeném příkladu máme relaci 723 blokovanou relací 1226. Relace 1226 je dále blokována relací 1796. Všimněte si, že všechny tři relace zadávají stejný dotaz s SQL ID cn7m7t6y5h77g .

Nyní, když známe SQL ID, můžeme snadno dotazovat V$SQL, abychom určili příkaz SQL, který je součástí problému. Tento dotaz jsem použil k získání dalších informací.

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

Výstup z dotazování V$SQL je následující:

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

Nyní vidíme, že tento dotaz má pouze 1 verzi v oblasti SQL. Okamžitě jsme tedy odstranili jednu z potenciálních problémových oblastí. V budoucím příspěvku na blogu budu diskutovat o dotazech s velkým počtem verzí v oblasti SQL. Ale to není náš dnešní problém, takže pokračujeme.

Z výše uvedeného by mělo být zřejmé, že existuje velmi vysoký počet volání analýzy. Dotaz byl proveden pouze 105krát, ale byl analyzován 3513krát. Fuj! Vysoké číslo, pokud jde o zneplatnění, s tím pravděpodobně také souvisí.

V tomto příkladu nyní máme dobrou představu o tom, v čem je problém. Toto je problém aplikace. Aplikace příliš analyzuje dotaz. Odešleme to tedy zpět do vývoje a prozkoumáme kód aplikace. Je třeba prozkoumat obvyklé důvody nadměrné analýzy.

Pokud by byl počet verzí nízký a nadměrná analýza/invalidace/načítání nebyl problém, pak bych měl podezření na chybu a podal SR podporu Oracle.


  1. Příklady MySQL REGEXP

  2. Sledování aktualizací synchronních statistik

  3. Jak mohu odstranit duplicitní řádky?

  4. Jak vytvořit pivotní dotaz na serveru SQL bez agregační funkce