Cuando una consulta no tiene un buen rendimiento y tarda demasiado en terminar, es necesario optimizarla. Pero estas optimizaciones muchas veces no son fáciles de ver a primera vista, ya que dependen del orden en el cual el motor de base de datos esté lanzando la query. Para analizar el comportamiento de la consulta, se suele recurrir al Explain Plan. En él podemos ver como se planifica la ejecución de la query y qué operaciones realiza en cada tabla.
El Explain Plan vendrá determinado por varios factores como pueden ser los índices creados, el volumen de las tablas y las estadísticas que el motor de base de datos ha obtenido por el uso de la misma. El problema suele venir cuando queremos analizar una query que no funciona bien en el entorno de Producción. Como el entorno de Producción no suele tener el mismo volumen de datos ni de uso que el de desarrollo -a no ser que se hagan copias a menudo- las estadísticas de ambos son distintas. Esto provoca que el explain plan de una misma consulta sea distinto y, por tanto, podrían no ser útiles las mejoras que planteemos en desarrollo.
Lo que se puede hacer es actualizar las estadísticas de las tablas de desarrollo, con las estadísticas actuales de producción. A continuación vamos a ver cómo exportar e importar estadísticas si estamos usando Oracle. Lo único que nos tenemos que asegurar es que ambos entornos sean iguales (tablas, índices, claves, …). Deberemos repetirlo por cada tabla que esté involucrada.
Creación de una tabla para las estadísticas en Oracle
Lo primero es crear una tabla para guardar las estadísticas con el siguiente comando.
execute dbms_stats.create_stat_table(nombre_esquema VARCHAR2, nombre_tabla VARCHAR2);
donde,
- nombre_esquema: nombre del esquema donde se creará la tabla para las estadísticas.
- nombre_tabla: nombre de la tabla que se utilizará para volcar los valores de las estadísticas de la tabla a analizar.
Un ejemplo de uso sería el siguiente:
execute dbms_stats.create_stat_table('usuario1', 'estadisticas_tabla1');
Exportar las estadísticas de una tabla
Para exportar las estadísticas de producción, que luego se importarán en el entorno de desarrollo, podemos usar el siguiente comando.
DBMS_STATS.EXPORT_TABLE_STATS (ownername VARCHAR2, tabname VARCHAR2, stattab VARCHAR2, statid VARCHAR2 DEFAULT NULL, cascade BOOLEAN DEFAULT TRUE, statown VARCHAR2 DEFAULT NULL);
donde,
- ownername: Nombre del esquema/usuario dueño de la tabla de la cual se van a exportar sus estadísticas.
- tabname: Nombre de la tabla de la que se van a exportar las estadísticas.
- stattab: Nombre de la tabla donde se van a guardar las estadísticas (Creada en el apartado anterior).
- statid: Identificador para las estadísticas. Es opcional pero es recomendable identificarlas (Creado en el apartado anterior).
- cascade: si deseamos exportar estadísticas de índices y columnas. Por defecto vale TRUE.
- statown: Quien es el dueño de la tabla de estadísticas.
Un ejemplo de uso sería el siguiente:
execute dbms_stats.export_table_stats('usuario1','tabla1', 'estadisticas_tabla1_prod','estadisticas_tabla1' ,true, 'usuario');
Es necesario exportar las estadísticas de producción a una tabla, ya que será esta tabla de estadísticas la que se importará en el ambiente de desarrollo.
Importar las estadísticas de una tabla
Tras haber exportado las estadísticas a una tabla (estadisticas_tabla1_prod) y haber copiado dicha tabla en el entorno donde deseamos importarlas (desarrollo), ahora sólo falta importarla para que el motor de base de datos sepa que queremos actualizar las estadísticas de la tabla con los datos que nos hemos traído. Por lo tanto las estadísticas existentes se reescribirán con las de producción.
La instrucción para ello, es la siguiente:
DBMS_STATS.IMPORT_TABLE_STATS (ownername VARCHAR2, tabname VARCHAR2, stattab VARCHAR2, statid VARCHAR2 DEFAULT NULL, cascade BOOLEAN DEFAULT TRUE, statown VARCHAR2 DEFAULT NULL);
donde,
- Ownername: Nombre del esquema/usuario dueño de la tabla a la cual asignar las estadísticas.
- Tabname: Nombre de la tabla a la sobreescribir las estadísticas.
- Stattab: Nombre de la tabla de la que leer las estadísticas a importar.
- Statid: Identificador para las estadísticas. Es opcional pero es recomendable identificarlas
- Cascade: Si deseamos importar estadísticas de índices y columnas. Por defecto tiene el valor true.
- Statown: El dueño de la tabla de estadísticas.
Un ejemplo de la llamada sería el siguiente.
execute dbms_stats.import_table_stats('usuario1','tabla1', 'estadisticas_tabla1_prod','estadisticas_tabla1' ,true, 'usuario');
Con esto, al lanzar el Explain Plan sobre esta tabla, los resultados de estadísticas Oracle ya serán idénticos a los de producción.
Si se desea recalcular estas estadísticas con los datos actuales de la base de datos de desarrollo, bastaría con lanzar la siguiente instrucción sobre la tabla deseada.
ANALYZE TABLE tabla1 COMPUTE STATISTICS;
Por otro lado, de la misma manera que hemos actualizado las estadísticas de una tabla, también se puede actualizar las de otros objetos. Para exportar, por ejemplo, existen los siguientes procedimientos.
EXPORT_COLUMN_STATS EXPORT_DATABASE_STATS EXPORT_DICTIONARY_STATS EXPORT_FIXED_OBJECTS_STATS EXPORT_INDEX_STATS EXPORT_SCHEMA_STATS EXPORT_SYSTEM_STATS EXPORT_TABLE_STATS