Oracle
 sql >> база данни >  >> RDS >> Oracle

курсор:щифт S изчакайте на X

В моята основна производствена RAC база данни виждам периоди на забавяне и доминиращото събитие за изчакване, в цялата система, е „курсор:щифт S чакане на X“. Събитието идва и си отива, но го виждам от време на време. Така че трябваше да разбера дъното на това. Имайте предвид, че това не е проблем с RAC. Това събитие може лесно да се види и в бази данни с един екземпляр. Когато виждам това на множество екземпляри на моята база данни Oracle RAC, това е защото имам множество сесии от едно и също приложение, разпределени между екземпляри, като всички правят едно и също нещо, като по този начин всички имат един и същ проблем.

Първо, какво представлява събитието чакане? Всяко от изчакванията на „cursor:“ представлява тесни места в споделения пул в SQL зоната. Преди много време тази част от Общия басейн беше защитена с резета. Но както е в случая с много области на споделения пул, Oracle вече използва мютексове. С промяната в механизма за защита вече имаме нови изчакващи събития.

В случай на това конкретно събитие за изчакване имаме курсор, който иска споделен щифт, но трябва да изчака друга сесия, за да освободи своя изключителен мютекс. Курсорът се опитва да бъде анализиран. Но не може да бъде анализиран синтактично, защото друга сесия поддържа същия мютекс.

Има три основни причини за сесиите, които чакат това събитие.

  • Високи твърди анализи
  • Голям брой версии на SQL израза
  • Бъгове

За съжаление има редица грешки, свързани с това чакане. Повечето от тези, които съм виждал, са коригирани в 11.2.0.4 или 12.1.0.1, така че ако изоставате във версиите, помислете за надграждане до една от по-новите версии на Oracle.

Така че нека видим дали можем да преминем през пример, за да определим причината за проблема. За да направя това, използвах следната заявка:

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

Изпълнявайки това в една от моите производствени RAC бази данни, получавам следния изход:

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

Първото нещо, което трябва да се отбележи, е, че мютексът е само в рамките на този екземпляр за Oracle RAC бази данни. За бази данни с един екземпляр заявката по-горе ще продължи да работи. За Oracle RAC изходът от тази заявка ще покаже кой екземпляр има проблема.

В примера по-горе имаме сесия 723, блокирана от сесия 1226. Сесия 1226 е допълнително блокирана от сесия 1796. Забележете, че и трите сесии издават една и съща заявка със SQL ID cn7m7t6y5h77g .

Сега, когато знаем SQL ID, можем лесно да потърсим V$SQL, за да определим SQL израза, участващ в проблема. Използвах тази заявка, за да получа повече информация.

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

Резултатът от запитването на V$SQL е както следва:

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

Вече можем да видим, че тази заявка има само 1 версия в SQL зоната. Така че веднага елиминирахме една от потенциалните проблемни области. В бъдеща публикация в блога ще обсъдя заявки с голям брой версии в SQL зоната. Но това не е нашият проблем днес, така че продължаваме.

От горното трябва да е очевидно, че има много голям брой извиквания за синтактичен анализ. Заявката е изпълнена само 105 пъти, но е анализирана 3513 пъти. Мда! Големият брой на анулирането вероятно също има нещо общо с това.

В този пример вече имаме добра представа какъв е проблемът. Това е проблем с приложението. Приложението прекомерно анализира заявката. Така че ще изпратим това обратно в разработката и ще разровим в кода на приложението. Обичайните причини за прекомерния анализ трябва да бъдат проучени.

Ако броят на версиите беше малък и прекомерният синтактичен анализ/невалидности/зареждания не беше проблем, тогава бих подозирал грешка и бих подавал SR в поддръжката на Oracle.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. По-бърз начин за вмъкване чрез скрипт в Oracle?

  2. Как да получите BLOB от файл в PL/SQL?

  3. Можете ли да използвате Microsoft Entity Framework с Oracle?

  4. Връщане на стойност от sql скрипт към shell скрипт

  5. Вмъкване на данни от SQL Server с Oracle® SQL*Loader