sql >> Base de Datos >  >> RDS >> Oracle

Estadísticas de la tabla GTT y SYS.WRI$_OPTSTAT_TAB_HISTORY

En 2015, actualicé nuestras bases de datos Oracle 11.2.0.4 a 12.1.0.2 y experimenté algunos problemas de rendimiento relacionados con nuestro uso de GTT. Escribí un blog sobre esos temas aquí.

El quid del problema que estaba tratando de resolver era que un cambio de comportamiento en 12c llevó a Oracle a guardar estadísticas de que el GTT tiene cero filas cuando no las tiene. Las estadísticas que muestran que el número de filas es igual a cero conducen a exploraciones de tablas completas y productos cartesianos en consultas que involucran el GTT. Como dije en esa publicación de blog, usamos DBMS_STATS.SET_TABLE_STATS después de llenar la tabla con datos para que cada sesión tuviera las estadísticas adecuadas para llegar a un mejor plan de ejecución.

Después de actualizar a Oracle 19c, comenzamos a ver otros problemas de rendimiento relacionados con GTT. Las consultas que usaban el GTT comenzaron a esperar en el evento de espera "pin del cursor:S esperar en X". Esto podría haber sido un cambio de comportamiento con la nueva versión de Oracle, pero también podría haber sido que nuestros desarrolladores usaran GTT con más frecuencia en nuestro código y no tuvieran nada que ver con la nueva versión.

Para las consultas involucradas en el evento de espera del pin del cursor, noté una gran cantidad de versiones de la instrucción SQL en el grupo compartido. Cuando consulté V$SQL_SHARED_CURSOR, descubrí que PURGED_CURSOR='Y' para estas declaraciones SQL. El cursor se está invalidando.

Al investigar este problema, descubrí que lo que sucede es que cada vez que llamamos a DBMS_STATS.SET_TABLE_STATS para obtener estadísticas basadas en la sesión en el GTT, invalida todas las declaraciones SQL que usan ese GTT. De ahí la espera. La espera no fue larga, por lo que muchos usuarios finales ni siquiera notaron el problema.

Pero entonces tuvimos un nuevo problema. Cuando realiza una llamada a SET_TABLE_STATS, Oracle escribe una entrada en SYS.WRI$_OPTSTAT_TAB_HISTORY y puede ver los valores que la sesión estableció para las estadísticas de la tabla. De forma predeterminada, esta tabla almacena 30 días de historial. La mesa estaba creciendo mucho y consumiendo la mayor parte de SYSAUX. De vez en cuando (¿cada hora?), Oracle eliminará las entradas que tengan más de 30 días. Esta poda regular de esta tabla ahora estaba afectando negativamente el rendimiento del usuario final. El siguiente es un gráfico de rendimiento de Lighty que muestra el impacto de la poda de esta tabla:

Todo ese color rojo aterrador es cuando las filas antiguas se eliminaban de SYS.WRI$_OPTSTAT_TAB_HISTORY.

Así que mi "corrección" de rendimiento hace cinco años introdujo otro problema de rendimiento. Para mejorar el rendimiento, lo que hice fue crear estadísticas compartidas en el GTT y dejar de usar estadísticas de sesión. Estos son los pasos:

--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 vez que las estadísticas compartidas estuvieron en su lugar, eliminamos las llamadas a DBMS_SET_TABLE_STATS de nuestro código.