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

Statistiche tabella GTT e SYS.WRI$_OPTSTAT_TAB_HISTORY

Nel 2015, ho aggiornato i nostri database Oracle 11.2.0.4 a 12.1.0.2 e ho riscontrato alcuni problemi di prestazioni relativi al nostro utilizzo di GTT. Ho bloggato su questi problemi qui.

Il punto cruciale del problema che stavo cercando di risolvere era che un cambiamento di comportamento in 12c ha portato Oracle a salvare le statistiche che GTT ha zero righe quando non lo fa. Le statistiche che mostrano il numero di righe uguale a zero portano a scansioni complete di tabelle e prodotti cartesiani su query che coinvolgono GTT. Come ho affermato in quel post sul blog, abbiamo utilizzato DBMS_STATS.SET_TABLE_STATS dopo aver popolato la tabella con i dati in modo che ogni sessione avesse statistiche adeguate per arrivare a un piano di esecuzione migliore.

Dopo l'aggiornamento a Oracle 19c, abbiamo iniziato a riscontrare altri problemi di prestazioni relativi al GTT. Le query che utilizzavano il GTT hanno iniziato ad attendere l'evento di attesa "pin cursore:S wait on X". Questo potrebbe essere stato un cambiamento di comportamento con la nuova versione di Oracle, ma potrebbero anche essere stati i nostri sviluppatori a utilizzare il GTT più spesso nel nostro codice e non avere nulla a che fare con la nuova versione.

Per le query coinvolte nell'evento di attesa del pin del cursore, ho notato un numero elevato di versioni dell'istruzione SQL nel pool condiviso. Quando ho interrogato V$SQL_SHARED_CURSOR, ho scoperto che PURGED_CURSOR='Y' per queste istruzioni SQL. Il cursore viene invalidato.

Durante la ricerca di questo problema, ho scoperto che ciò che accade è che ogni volta che abbiamo chiamato DBMS_STATS.SET_TABLE_STATS per ottenere statistiche basate sulla sessione su GTT, invalida tutte le istruzioni SQL che utilizzano quel GTT. Da qui l'attesa. L'attesa non è stata lunga, quindi molti utenti finali non hanno nemmeno notato il problema.

Ma poi abbiamo avuto un nuovo problema. Quando effettui una chiamata a SET_TABLE_STATS, Oracle scrive una voce in SYS.WRI$_OPTSTAT_TAB_HISTORY e puoi vedere i valori impostati dalla sessione per le statistiche della tabella. Per impostazione predefinita, questa tabella memorizza 30 giorni di cronologia. Il tavolo stava crescendo molto e consumava la maggior parte di SYSAUX. Ogni tanto (ogni ora?) Oracle rimuove le voci più vecchie di 30 giorni. Questa regolare eliminazione di questa tabella ora influiva negativamente sulle prestazioni degli utenti finali. Di seguito è riportato un grafico delle prestazioni di Lighty che mostra l'impatto della potatura di questa tabella:

Tutto quel colore rosso spaventoso è quando le vecchie righe venivano rimosse da SYS.WRI$_OPTSTAT_TAB_HISTORY.

Quindi la mia "correzione" delle prestazioni cinque anni fa ha introdotto un altro problema di prestazioni. Per migliorare le prestazioni, quello che ho fatto è stato creare statistiche condivise sul GTT e smettere di usare le statistiche di sessione. Ecco i passaggi:

--set prefs to SHARED globally      
exec DBMS_STATS.set_global_prefs ( pname => 'GLOBAL_TEMP_TABLE_STATS', pvalue => 'SHARED');
--set the table and index stats
exec dbms_stats.set_table_stats(ownname=>'MY_SCHEMA',tabname=>'MY_GTT_TABLE',numrows=>1000,numblks=>2,avgrlen=>15);
exec dbms_stats.set_index_stats(ownname=>'MY_SCHEMA',indname=>'GTT_INDEX',indlevel=>1,numlblks=>2,numdist=>15,clstfct=>28,numrows=>1000);
-- set prefs back to SESSION
exec DBMS_STATS.set_global_prefs ( pname => 'GLOBAL_TEMP_TABLE_STATS', pvalue => 'SESSION');
-- verify stats set
select num_rows,blocks,last_analyzed,scope
from dba_tab_statistics
where table_name ='MY_GTT_TABLE';
select blevel,leaf_blocks,distinct_keys,num_rows,clustering_factor,last_analyzed,scope
from dba_ind_statistics
where index_name='GTT_INDEX' and owner='MY_SCHEMA';

Una volta impostate le statistiche condivise, rimuoviamo le chiamate a DBMS_SET_TABLE_STATS dal nostro codice.