В моята основна производствена 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.