Oracle
 sql >> Database >  >> RDS >> Oracle

cursore:pin S aspetta su X

Sul mio database RAC di produzione principale, vedo periodi di lentezza e l'evento di attesa dominante, a livello di sistema, è "cursore:pin S wait su X". L'evento va e viene, ma di tanto in tanto lo vedo. Quindi avevo bisogno di andare in fondo a questo. Si noti che questo non è un problema RAC. Questo evento può essere facilmente visualizzato anche su database a istanza singola. Quando lo vedo su più istanze del mio database Oracle RAC, è perché ho più sessioni della stessa applicazione distribuite tra le istanze, che fanno tutte la stessa cosa, quindi tutte hanno lo stesso problema.

Innanzitutto, di cosa tratta l'evento wait? Qualsiasi delle attese del "cursore:" sono colli di bottiglia nel pool condiviso nell'area SQL. Molto tempo fa, questa porzione della Piscina Condivisa era protetta da chiavistelli. Ma come nel caso di molte aree del pool condiviso, Oracle ora utilizza i mutex. Con la modifica del meccanismo di protezione, ora abbiamo nuovi eventi di attesa.

Nel caso di questo particolare evento di attesa, abbiamo un cursore che desidera un pin condiviso ma deve attendere che un'altra sessione rilasci il suo mutex esclusivo. Un cursore sta tentando di essere analizzato. Ma non può essere analizzato perché un'altra sessione sta trattenendo lo stesso mutex.

Ci sono tre cause principali per le sessioni in attesa di questo evento.

  • Analisi molto difficili
  • Un numero elevato di versioni dell'istruzione SQL
  • Bug

Sfortunatamente, ci sono una serie di bug relativi a questo evento di attesa. La maggior parte di quelli che ho visto sono stati corretti in 11.2.0.4 o 12.1.0.1, quindi se sei in ritardo nelle versioni, considera l'aggiornamento a una delle versioni Oracle più recenti.

Quindi vediamo se possiamo fare un esempio per determinare la causa del problema. Per farlo, ho usato la seguente query:

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

Eseguendo questo in uno dei miei database RAC di produzione, ottengo il seguente output:

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

La prima cosa da notare è che il mutex è solo all'interno di quell'istanza per i database Oracle RAC. Per i database a istanza singola, la query precedente continuerà a funzionare. Per Oracle RAC, l'output di questa query mostrerà quale istanza presenta il problema.

Nell'esempio sopra, abbiamo la sessione 723 bloccata dalla sessione 1226. La sessione 1226 è ulteriormente bloccata dalla sessione 1796. Si noti che tutte e tre le sessioni emettono la stessa query con ID SQL cn7m7t6y5h77g .

Ora che conosciamo l'ID SQL, possiamo facilmente interrogare V$SQL per determinare l'istruzione SQL coinvolta nel problema. Ho usato questa query per ottenere maggiori informazioni.

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

L'output della query su V$SQL è il seguente:

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

Ora possiamo vedere che questa query ha solo 1 versione nell'area SQL. Quindi abbiamo subito eliminato una delle potenziali aree problematiche. In un futuro post sul blog, discuterò le query con un numero elevato di versioni nell'area SQL. Ma questo non è il nostro problema oggi, quindi procediamo.

Dovrebbe essere ovvio da quanto sopra che esiste un numero molto elevato di chiamate di analisi. La query è stata eseguita solo 105 volte ma è stata analizzata 3513 volte. Accidenti! Il numero elevato di invalidazioni probabilmente ha qualcosa a che fare anche con questo.

In questo esempio, ora abbiamo una buona idea di quale sia il problema. Questo è un problema di applicazione. L'applicazione esegue un'analisi eccessiva della query. Quindi lo rispediremo allo sviluppo e analizzeremo il codice dell'applicazione. È necessario esaminare i soliti motivi per un'analisi eccessiva.

Se il numero di versioni fosse basso e l'analisi/invalidazioni/caricamenti eccessivi non fosse un problema, allora sospetterei un bug e presenterei un SR con Oracle Support.