Oracle
 sql >> Base de données >  >> RDS >> Oracle

Statistiques de la table GTT et SYS.WRI$_OPTSTAT_TAB_HISTORY

En 2015, j'ai mis à niveau nos bases de données Oracle 11.2.0.4 vers 12.1.0.2 et j'ai rencontré des problèmes de performances liés à notre utilisation des GTT. J'ai blogué sur ces questions ici.

Le nœud du problème que j'essayais de résoudre était qu'un changement de comportement dans 12c conduisait à ce qu'Oracle enregistre des statistiques selon lesquelles le GTT n'a aucune ligne alors qu'il n'en a pas. Les statistiques montrant que le nombre de lignes est égal à zéro conduisent à des analyses de table complètes et à des produits cartésiens sur les requêtes impliquant le GTT. Comme je l'ai indiqué dans ce billet de blog, nous avons utilisé DBMS_STATS.SET_TABLE_STATS après avoir rempli la table avec des données afin que chaque session ait des statistiques appropriées pour arriver à un meilleur plan d'exécution.

Après la mise à niveau vers Oracle 19c, nous avons commencé à voir d'autres problèmes de performances liés au GTT. Les requêtes qui utilisaient le GTT ont commencé à attendre l'événement d'attente "cursor pin:S wait on X". Cela aurait pu être un changement de comportement avec la nouvelle version d'Oracle, mais cela aurait aussi pu être nos développeurs utilisant le GTT plus souvent dans notre code et n'ayant rien à voir avec la nouvelle version.

Pour les requêtes impliquées dans l'événement d'attente Cursor Pin, j'ai remarqué un nombre élevé de versions de l'instruction SQL dans le pool partagé. Lorsque j'ai interrogé V$SQL_SHARED_CURSOR, j'ai découvert que PURGED_CURSOR='Y' pour ces instructions SQL. Le curseur devient invalide.

Lors de la recherche de ce problème, j'ai découvert que ce qui se passe, c'est que chaque fois que nous appelons DBMS_STATS.SET_TABLE_STATS pour obtenir des statistiques basées sur la session sur le GTT, cela invalide toutes les instructions SQL qui utilisent ce GTT. D'où l'attente. L'attente n'a pas été longue, de nombreux utilisateurs finaux n'ont même pas remarqué le problème.

Mais ensuite nous avons eu un nouveau problème. Lorsque vous appelez SET_TABLE_STATS, Oracle écrit une entrée dans SYS.WRI$_OPTSTAT_TAB_HISTORY et vous pouvez voir les valeurs définies par la session pour les statistiques de la table. Par défaut, cette table stocke 30 jours d'historique. La table grandissait très largement et consommait la majeure partie de SYSAUX. De temps en temps (toutes les heures ?), Oracle supprimera les entrées datant de plus de 30 jours. Cet élagage régulier de cette table avait désormais un impact négatif sur les performances de l'utilisateur final. Voici un graphique de performances de Lighty montrant l'impact de l'élagage de cette table :

Toute cette couleur rouge effrayante est lorsque les anciennes lignes ont été supprimées de SYS.WRI$_OPTSTAT_TAB_HISTORY.

Donc, mon "correctif" de performances il y a cinq ans a introduit un autre problème de performances. Pour améliorer les performances, j'ai créé des statistiques partagées sur le GTT et cessé d'utiliser les statistiques de session. Voici les étapes :

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

Une fois les statistiques partagées en place, nous supprimons les appels à DBMS_SET_TABLE_STATS de notre code.