In meiner Hauptproduktions-RAC-Datenbank sehe ich Perioden der Langsamkeit und das dominante Warteereignis, systemweit, ist „Cursor:Pin S Wait on X“. Das Ereignis kommt und geht, aber ich sehe es von Zeit zu Zeit. Also musste ich dem auf den Grund gehen. Beachten Sie, dass dies kein RAC-Problem ist. Dieses Ereignis ist auch in Einzelinstanzdatenbanken leicht zu sehen. Wenn ich dies auf mehreren Instanzen meiner Oracle RAC-Datenbank sehe, liegt das daran, dass ich mehrere Sitzungen derselben Anwendung auf die Instanzen verteilt habe, die alle dasselbe tun und daher alle dasselbe Problem haben.
Erstens, worum geht es beim Wait-Event? Alle „Cursor:“-Wartezeiten sind Engpässe im Shared Pool im SQL-Bereich. Vor langer Zeit war dieser Teil des Shared Pools durch Riegel geschützt. Aber wie in vielen Bereichen des Shared Pools verwendet Oracle jetzt Mutexe. Mit der Änderung des Schutzmechanismus haben wir jetzt neue Warteereignisse.
Im Fall dieses speziellen Warteereignisses haben wir einen Cursor, der einen freigegebenen Pin haben möchte, aber auf eine andere Sitzung warten muss, um seinen exklusiven Mutex freizugeben. Ein Cursor versucht, analysiert zu werden. Aber es kann nicht geparst werden, weil eine andere Sitzung am gleichen Mutex festhält.
Es gibt drei Hauptursachen dafür, dass Sitzungen auf dieses Ereignis warten.
- Hohe harte Parses
- Eine große Anzahl von Versionen der SQL-Anweisung
- Fehler
Leider gibt es eine Reihe von Fehlern im Zusammenhang mit diesem Warteereignis. Die meisten, die ich gesehen habe, wurden in 11.2.0.4 oder 12.1.0.1 behoben. Wenn Sie also in Versionen hinterherhinken, ziehen Sie ein Upgrade auf eine der neueren Oracle-Versionen in Betracht.
Sehen wir uns also an, ob wir ein Beispiel durchgehen können, um die Ursache des Problems zu ermitteln. Dazu habe ich die folgende Abfrage verwendet:
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';
Wenn ich dies in einer meiner Produktions-RAC-Datenbanken ausführe, erhalte ich die folgende Ausgabe:
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
Als Erstes ist zu beachten, dass sich der Mutex nur innerhalb dieser Instanz für Oracle RAC-Datenbanken befindet. Bei Einzelinstanzdatenbanken funktioniert die obige Abfrage weiterhin. Für Oracle RAC zeigt die Ausgabe dieser Abfrage, bei welcher Instanz das Problem auftritt.
Im obigen Beispiel haben wir Sitzung 723 durch Sitzung 1226 blockiert. Sitzung 1226 wird außerdem durch Sitzung 1796 blockiert. Beachten Sie, dass alle drei Sitzungen dieselbe Abfrage mit der SQL-ID cn7m7t6y5h77g ausgeben .
Da wir nun die SQL-ID kennen, können wir V$SQL ganz einfach abfragen, um die an dem Problem beteiligte SQL-Anweisung zu ermitteln. Ich habe diese Abfrage verwendet, um weitere Informationen zu erhalten.
select sql_id,loaded_versions,executions,loads,invalidations,parse_calls from gv$sql where inst_id=4 and sql_id='cn7m7t6y5h77g';
Die Ausgabe der Abfrage von V$SQL lautet wie folgt:
SQL_ID LOADED_VERSIONS EXECUTIONS LOADS INVALIDATIONS PARSE_CALLS ------------- --------------- ---------- ---------- ------------- ----------- cn7m7t6y5h77g 1 105 546 308 3513
Wir können jetzt sehen, dass diese Abfrage nur eine Version im SQL-Bereich hat. Also haben wir gleich einen der potenziellen Problembereiche beseitigt. In einem zukünftigen Blogbeitrag werde ich Abfragen mit hoher Versionsanzahl im SQL-Bereich besprechen. Aber das ist heute nicht unser Problem, also machen wir weiter.
Aus dem Obigen sollte ersichtlich sein, dass es eine sehr hohe Anzahl von Parsing-Aufrufen gibt. Die Abfrage wurde nur 105 Mal ausgeführt, aber 3513 Mal geparst. Huch! Die hohe Zahl an Ungültigkeitserklärungen hat wahrscheinlich auch damit zu tun.
In diesem Beispiel haben wir jetzt eine gute Vorstellung davon, was das Problem ist. Dies ist ein Anwendungsproblem. Die Anwendung analysiert die Abfrage übermäßig. Wir senden dies also zurück an die Entwicklung und untersuchen den Anwendungscode. Die üblichen Gründe für das Überparsen müssen untersucht werden.
Wenn die Anzahl der Versionen niedrig wäre und übermäßiges Parsen/Invalidierungen/Laden kein Problem wäre, würde ich einen Fehler vermuten und eine SR beim Oracle-Support einreichen.