Oracle
 sql >> Baza danych >  >> RDS >> Oracle

kursor:pin S czekaj na X

W mojej głównej produkcyjnej bazie danych RAC widzę okresy spowolnienia, a dominującym zdarzeniem oczekiwania w całym systemie jest „kursor:pin S czekaj na X”. Wydarzenie przychodzi i odchodzi, ale od czasu do czasu je widzę. Więc musiałem poznać sedno tego. Zauważ, że nie jest to problem RAC. To zdarzenie można łatwo zobaczyć również w bazach danych o jednym wystąpieniu. Kiedy widzę to w wielu instancjach mojej bazy danych Oracle RAC, dzieje się tak dlatego, że mam wiele sesji z tej samej aplikacji rozłożonych między instancjami, wszystkie robią to samo, a zatem wszystkie mają ten sam problem.

Po pierwsze, o co chodzi w przypadku oczekiwania? Każde z czekań „kursora:” jest wąskim gardłem w puli współdzielonej w obszarze SQL. Dawno temu ta część wspólnej puli była chroniona zatrzaskami. Ale tak jak w przypadku wielu obszarów puli współdzielonej, Oracle używa teraz muteksów. Wraz ze zmianą mechanizmu ochrony mamy teraz nowe zdarzenia oczekiwania.

W przypadku tego konkretnego zdarzenia oczekiwania mamy kursor, który chce udostępnić pin, ale musi poczekać na kolejną sesję, aby zwolnić swój wyłączny muteks. Kursor próbuje zostać przeanalizowany. Ale nie można go przeanalizować, ponieważ inna sesja utrzymuje ten sam muteks.

Sesje oczekujące na to wydarzenie mają trzy główne przyczyny.

  • Wysokie twarde parsowanie
  • Duża liczba wersji instrukcji SQL
  • Błędy

Niestety, istnieje wiele błędów związanych z tym zdarzeniem oczekiwania. Większość z tych, które widziałem, została naprawiona w 11.2.0.4 lub 12.1.0.1, więc jeśli masz opóźnienia w wersjach, rozważ aktualizację do jednej z nowszych wersji Oracle.

Zobaczmy więc, czy możemy przejść przez przykład, aby określić przyczynę problemu. W tym celu użyłem następującego zapytania:

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

Uruchamiając to w jednej z moich produkcyjnych baz danych RAC, otrzymuję następujące dane wyjściowe:

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

Pierwszą rzeczą, na którą należy zwrócić uwagę, jest to, że mutex znajduje się tylko w tej instancji dla baz danych Oracle RAC. W przypadku baz danych o jednym wystąpieniu powyższe zapytanie będzie nadal działać. W przypadku Oracle RAC dane wyjściowe tego zapytania pokażą, w której instancji występuje problem.

W powyższym przykładzie mamy sesję 723 blokowaną przez sesję 1226. Sesja 1226 jest dodatkowo blokowana przez sesję 1796. Zauważ, że wszystkie trzy sesje wysyłają to samo zapytanie z identyfikatorem SQL cn7m7t6y5h77g .

Teraz, gdy znamy identyfikator SQL, możemy łatwo wysłać zapytanie do V$SQL, aby określić instrukcję SQL związaną z problemem. Użyłem tego zapytania, aby uzyskać więcej informacji.

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

Wynik zapytania V$SQL jest następujący:

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

Widzimy teraz, że to zapytanie ma tylko 1 wersję w obszarze SQL. Dlatego od razu wyeliminowaliśmy jeden z potencjalnych obszarów problemowych. W przyszłym wpisie na blogu omówię zapytania z dużą liczbą wersji w obszarze SQL. Ale to nie jest dzisiaj nasz problem, więc kontynuujemy.

Z powyższego powinno być oczywiste, że istnieje bardzo duża liczba wywołań parsowania. Zapytanie zostało wykonane tylko 105 razy, ale zostało przeanalizowane 3513 razy. Ojej! Wysoka liczba unieważnień prawdopodobnie ma z tym coś wspólnego.

W tym przykładzie mamy teraz dobre pojęcie o tym, na czym polega problem. To jest problem z aplikacją. Aplikacja nadmiernie analizuje zapytanie. Więc odeślemy to z powrotem do rozwoju i zagłębimy się w kod aplikacji. Należy zbadać zwykłe powody nadmiernej analizy.

Gdyby liczba wersji była niska, a nadmierne analizowanie/unieważnianie/ładowania nie stanowiło problemu, podejrzewałbym błąd i wysłałby SR do Oracle Support.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Funkcja NLS_UPPER() w Oracle

  2. Jak używać tablicy asocjacyjnej Oracle w zapytaniu SQL

  3. Konwertuj rozdzielany ciąg na wiersze w Oracle

  4. Kiedy należy zagnieżdżać bloki PL/SQL BEGIN...END?

  5. WSTAW i AKTUALIZUJ rekord za pomocą kursorów w oracle