DBA

Mostrando las entradas con la etiqueta DBA. Mostrar todas las entradas
Mostrando las entradas con la etiqueta DBA. Mostrar todas las entradas

miércoles, 30 de septiembre de 2026

Mantenimiento y purgado de STATSPACK en Oracle (PERFSTAT)


En más de una ocasión, los que administramos bases de datos donde no disponemos de licenciamiento para el Diagnostics Pack nos apoyamos en Statspack como nuestra principal herramienta de diagnóstico histórico. Sin embargo, si no mantenemos una política de limpieza estricta, el esquema PERFSTAT puede crecer de forma desmesurada en nuestros discos.

Continuando con las buenas prácticas para mantener saludable nuestro esquema PERFSTAT, hoy veremos un enfoque de control absoluto: cómo purgar por rangos específicos de snap_id, cómo recuperar físicamente el espacio en disco mediante el comando SHRINK SPACE y algunas recomendaciones de rendimiento asociadas.

Antes de ejecutar cualquier acción, el primer paso es consultar los snapshots disponibles en el repositorio para definir con exactitud el rango que deseamos eliminar.

Nota: Ejecuta la siguiente consulta conectado con el usuario administrador o PERFSTAT:

SELECT snap_id, snap_time
FROM perfstat.stats$snapshot
ORDER BY snap_id ASC;


Además, puedes revisar cuánto espacio están consumiendo actualmente las tablas más pesadas antes de iniciar el mantenimiento.

SELECT segment_name,ROUND(SUM(bytes)/1024/1024/1024, 2) AS size_gb
FROM dba_segments
WHERE owner = 'PERFSTAT' 
AND segment_name IN ('STATS$SQL_SUMMARY', 'STATS$SQLTEXT', 'STATS$FILESTATXS')
GROUP BY segment_name
ORDER BY size_gb DESC;


Una vez definido el intervalo, utilizamos el procedimiento statspack.purge especificando los parámetros de rango i_begin_snap e i_end_snap:
BEGIN 
perfstat.statspack.purge( i_begin_snap => 90160 , i_end_snap => 106699); 
END; 
/ 
COMMIT;
 

Al realizar un purge, las filas son eliminadas de las tablas, pero los segmentos lógicos (High Water Mark) y el espacio en los ficheros de datos no se liberan automáticamente de forma predeterminada. Las tablas siguen reteniendo el tamaño anterior en disco.

Para compactar las tablas más pesadas del esquema PERFSTAT y devolver el espacio libre al tablespace, aplicamos la habilitación de movimiento de filas (ROW MOVEMENT) y el comando SHRINK SPACE:

-- 1. Mantenimiento sobre STATS$SQL_SUMMARY 
ALTER TABLE perfstat.STATS$SQL_SUMMARY ENABLE ROW MOVEMENT; 
ALTER TABLE perfstat.STATS$SQL_SUMMARY SHRINK SPACE; 
ALTER TABLE perfstat.STATS$SQL_SUMMARY DISABLE ROW MOVEMENT; 

-- 2. Mantenimiento sobre STATS$SQLTEXT 
ALTER TABLE perfstat.STATS$SQLTEXT ENABLE ROW MOVEMENT; 
ALTER TABLE perfstat.STATS$SQLTEXT SHRINK SPACE; 
ALTER TABLE perfstat.STATS$SQLTEXT DISABLE ROW MOVEMENT; 

  -- 3. Mantenimiento sobre STATS$FILESTATXS 
ALTER TABLE perfstat.STATS$FILESTATXS ENABLE ROW MOVEMENT; 
ALTER TABLE perfstat.STATS$FILESTATXS SHRINK SPACE; 
ALTER TABLE perfstat.STATS$FILESTATXS DISABLE ROW MOVEMENT;


Recomendación: Este tipo de operaciones de SHRINK generan bloqueos momentáneos y consumo de recursos, por lo que se recomienda ejecutarlas en ventanas de mantenimiento o periodos de baja actividad (fuera de horario pico).

Volvemos a revisar cuánto espacio están consumiendo actualmente las tablas más pesadas después de ejecutado el mantenimiento. Observamos un decrecimiento en el consumo por parte de 2 de ellas.


Tras un proceso masivo de borrado y compactación física de tablas, los índices asociados pueden quedar fragmentados. Para asegurar que el optimizador de Oracle continúe accediendo de manera óptima a los datos, puedes reconstruir los índices principales en línea:
ALTER INDEX perfstat.stats$sql_summary_pk REBUILD ONLINE; 
ALTER INDEX perfstat.stats$sqltext_pk REBUILD ONLINE;
El mantenimiento preventivo de Statspack es una tarea ineludible para cualquier DBA que gestione entornos sin Diagnostics Pack. Purgar los datos históricos innecesarios y recuperar el espacio físico liberado es un proceso sencillo pero crítico. Implementando esta rutina mantendrás tus bases de datos optimizadas, evitarás alertas innecesarias por falta de espacio y asegurarás diagnósticos precisos por mucho más tiempo.

Saludos.

 

miércoles, 26 de agosto de 2026

Cómo solucionar el ORA-01555: Diagnóstico y cálculo real del Undo Retention


¡Hola a todos! En esta ocasión vamos a revisar un error clásico con el que nos topamos los administradores de bases de datos Oracle en el día a día: el célebre ORA-01555: snapshot too old.

Cuando este mensaje aparece en los logs, la reacción impulsiva suele ser subir el parámetro UNDO_RETENTION o inflar el tablespace sin un análisis previo. Veamos cómo diagnosticarlo correctamente utilizando las vistas del sistema, cómo calcular el valor ideal y qué alternativas reales existen para solucionarlo.

Cuando ocurre el error, Oracle indica qué sentencia SQL falló y cuánto tiempo llevaba ejecutándose. Para entender el comportamiento general de las consultas de lectura consistente y la retención real, podemos consultar la vista V$UNDOSTAT con el siguiente script:

SELECT BEGIN_TIME, END_TIME, UNDOTSN AS Tablespace_ID,
UNDOBLKS AS Bloques_Generados, TXNCOUNT AS Transacciones,
MAXQUERYLEN AS Query_Mas_Largo_Seg, TUNED_UNDORETENTION AS Retencion_Autotuneada_Seg
FROM V$UNDOSTAT 
WHERE MAXQUERYLEN IS NOT NULL ORDER BY MAXQUERYLEN DESC;


Como se observa, el tiempo del query más largo (QUERY_MAS_LARGO_SEG) ronda consistentemente cerca de las 4 horas (14,184 segundos) debido a procesos analíticos o reportes pesados recurrentes. Oracle intenta autoajustar la retención (RETENCION_AUTOTUNEADA_SEG), pero si el espacio físico no es suficiente, el undo expira antes de tiempo y surge el fallo.

Para evitar adivinar números al azar, podemos apoyarnos en la tasa real de generación de bloques de nuestro entorno. Utiliza la siguiente consulta para calcular los Gigabytes exactos requeridos en el Tablespace de Undo para soportar una ventana de tiempo determinada.

SELECT 
    t.gb_undo_actual,
    n.gb_undo_necesarios,
    CASE 
        WHEN t.gb_undo_actual >= n.gb_undo_necesarios THEN 'SUFICIENTE'
        ELSE 'FALTA ESPACIO'
    END AS estado_undo
FROM 
    (SELECT ROUND(SUM(bytes) / (1024 * 1024 * 1024), 2) AS gb_undo_actual 
     FROM dba_data_files 
     WHERE tablespace_name = (SELECT value FROM v$parameter WHERE name = 'undo_tablespace')) t,
     --Reemplaza el valor de 14184 por tu valor más alto obtenido de la consulta anterior en la columna "Query_Mas_Largo_Seg"
    (SELECT ROUND( ( 14184 * 
                     (SELECT MAX(UNDOBLKS / ((END_TIME - BEGIN_TIME) * 86400)) FROM V$UNDOSTAT) * 
                     (SELECT TO_NUMBER(VALUE) FROM V$PARAMETER WHERE NAME = 'db_block_size') 
                   ) / (1024 * 1024 * 1024), 2 ) AS gb_undo_necesarios 
     FROM dual) n;


Como podemos ver en este análisis, aunque el proceso es demandante, nuestro tablespace cuenta con 543.99 GB actuales frente a los 450.89 GB requeridos, arrojando un estatus de SUFICIENTE en cuanto a espacio físico.

Si un reporte tarda casi 4 horas en ejecutarse, subir el parámetro UNDO_RETENTION globalmente a ese nivel extremo puede inflar innecesariamente el tablespace para toda la transaccionalidad normal del sistema.

Para evitar que el autoajuste de Oracle se base en picos anómalos, podemos calcular un valor de retención inteligente basado exclusivamente en la operación estándar de la base de datos:

SELECT 
    ROUND(AVG(TUNED_UNDORETENTION)) AS UNDO_RETENTION_SUGERIDO_SEG
FROM V$UNDOSTAT
WHERE MAXQUERYLEN < 3600; -- Excluimos queries mayores a 1 hora (reportes pesados)


 Esto te dará un valor equilibrado para proteger el día a día sin sobredimensionar la retención por culpa de una sola consulta analítica.

Tienes dos caminos posibles para decidir cómo proceder:

Opción A: Ampliar el Undo

Si el reporte es un proceso heredado o una consulta analítica que por naturaleza debe tardar horas, debes aceptar el costo de almacenamiento:

  1. Modifica el parámetro UNDO_RETENTION en segundos (cubriendo holgadamente el tiempo del proceso, por ejemplo, 15,100 segundos):

    ALTER SYSTEM SET undo_retention = 15100 SCOPE=BOTH; 

  2. Si requieres asegurar estrictamente que Oracle no sobrescriba el undo antes de cumplir ese tiempo (garantizando el espacio físico previamente dimensionado):

    ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;

    Nota: Ten en cuenta que con RETENTION GUARANTEE, si el tablespace se llena por completo, las nuevas transacciones que requieran espacio fallarán. ¡Asegúrate de haber dimensionado bien el espacio físico antes de activarlo!

  3. Para revertir en caso de emergencia por espacio:

    ALTER TABLESPACE undotbs1 RETENTION NOGUARANTEE; 

Opción B: Tunear la consulta

Un proceso analítico o reporte que tarde casi 4 horas suele ser un candidato ideal para optimización. En lugar de gastar gigabytes de disco guardando transacciones viejas, conviene:

  • Revisar planes de ejecución y crear o ajustar índices faltantes.

  • Migrar consultas pesadas a procesamiento en paralelo (PARALLEL).

  • Particionar las tablas involucradas para que el motor lea solo lo necesario.

  • Reducir el tiempo de ejecución elimina automáticamente la necesidad de un tablespace de undo gigantesco.

En resumen, modificar UNDO_RETENTION o configurar un RETENTION GUARANTEE funciona excelente como un parche rápido para salir del paso, pero la verdadera habilidad de un DBA se demuestra yendo directo a la raíz: optimizar los procesos.

Al final, lograr que tus consultas sean eficientes no solo te ahorra dolores de cabeza con el odioso ORA-01555, sino que también optimiza el rendimiento general del motor y evita que desperdicies espacio valioso en los discos.

Saludos.


 

lunes, 20 de julio de 2026

Restablecer la contraseña de un usuario expirado sin conocer la clave actual en Oracle 12c / 19c



En la administración diaria de bases de datos Oracle, es habitual encontrarnos con un escenario crítico: una cuenta de usuario (ya sea de aplicación, de servicio o de integración) pasa a estado EXPIRED debido a las políticas del perfil de seguridad asignado.

El verdadero problema surge cuando nadie recuerda la contraseña original. Si la cambiamos por una clave completamente nueva, interrumpiremos de inmediato el servicio de las aplicaciones o sistemas dependientes hasta que sus cadenas de conexión sean actualizadas, algo que no siempre es posible realizar de manera inmediata en entornos de producción.

Para resolver esta contingencia sin alterar la contraseña real y ganar tiempo para gestionar el cambio formal, podemos "refrescar" el estado de la cuenta (recomponiendo su estatus a OPEN) reasignando su mismo hash almacenado en el diccionario de datos.

En versiones antiguas de Oracle (10g / 11g), solía extraerse la columna PASSWORD de la tabla sys.user$. Sin embargo, a partir de Oracle 12c, 19c y versiones superiores, el motor utiliza algoritmos de cifrado más avanzados (SHA-2). Por ello, el hash activo para la autenticación se almacena en la columna SPARE4.

A continuación, se detalla el procedimiento paso a paso para realizar esta acción de contingencia en cualquier usuario de la base de datos.

Si estás trabajando en entornos Oracle 12c, 19c o superiores bajo la arquitectura Multitenant, recuerda que antes de ejecutar este procedimiento debes asegurarte de estar conectado en el contenedor correcto:

  • Si el usuario afectado es un Common User (ej. C##APP_USER), deberás ejecutarlo desde el CDB$ROOT.

  • Si es un usuario local de una aplicación, debes moverte primero a su PDB correspondiente: ALTER SESSION SET CONTAINER = mi_pdb;

Antes de realizar cualquier ajuste, confirmamos el estado de la cuenta y el perfil asociado consultando la vista DBA_USERS:

SELECT username, account_status, profile, expiry_date FROM dba_users WHERE username = 'USUARIO';

Para evitar el error ORA-28007: the password cannot be reused, debemos verificar si el perfil asignado permite la reasignación de la misma clave. Consultamos DBA_PROFILES:

SELECT resource_name, limit FROM dba_profiles WHERE profile = (SELECT profile FROM dba_users WHERE username = 'USUARIO') AND resource_name IN ('PASSWORD_REUSE_TIME', 'PASSWORD_REUSE_MAX');

  • Si ambos valores son UNLIMITED: Se puede avanzar al siguiente paso.
  • Si tienen un límite numérico restrictivo: Se pueden modificar temporalmente los parámetros del perfil antes de ejecutar el cambio, para este caso en particular tenia asignado el perfil "default":
ALTER PROFILE DEFAULT LIMIT PASSWORD_REUSE_TIME UNLIMITED PASSWORD_REUSE_MAX UNLIMITED;

Nota: Si tu usuario tiene un perfil personalizado, reemplaza DEFAULT por el nombre de su perfil para no alterar las políticas globales de la base de datos.

Consultamos la tabla interna sys.user$ filtrando por el nombre del usuario afectado:

SELECT spare4 FROM sys.user$ WHERE name = 'USUARIO';

La consulta devolverá la cadena alfanumérica completa correspondiente al hash de autenticación: 


Es importante copiar la cadena devuelta por SPARE4 en su totalidad (incluyendo prefijos como S: o T:), ya que especifica el tipo de algoritmo de cifrado empleado por la versión de la base de datos.

Ejecutamos la sentencia ALTER USER utilizando la cláusula IDENTIFIED BY VALUES. Esta sintaxis le indica a Oracle que registre directamente la clave procesada sin aplicar una nueva función de hashing sobre la cadena:
ALTER USER USUARIO IDENTIFIED BY VALUES 'S:A8B9C0D1E2F3...[HASH_COMPLETO_AQUÍ]...';


Nota: Si la cuenta también se encontraba bloqueada (LOCKED), se puede incluir la cláusula ACCOUNT UNLOCK en la misma sentencia

Con esto, el motor revalida el hash, calcula la nueva fecha de vencimiento según el perfil y cambia el estado de la cuenta a OPEN.

Validamos nuevamente la vista DBA_USERS para verificar que el procedimiento se haya completado exitosamente:
SELECT username, account_status, expiry_date FROM dba_users WHERE username = 'USUARIO';

El estado cambiará a OPEN y la columna EXPIRY_DATE reflejará la nueva fecha de vencimiento.

Si en los pasos anteriores modificaste los parámetros de reutilización de contraseña, no olvides regresar el perfil a sus valores originales para mantener el estándar de seguridad de la organización:
ALTER PROFILE DEFAULT LIMIT PASSWORD_REUSE_TIME 365 PASSWORD_REUSE_MAX 3;

Este procedimiento constituye una herramienta de contingencia fundamental para el DBA al momento de resolver bloqueos de servicio urgentes en aplicaciones cuyas contraseñas no puedan modificarse de forma inmediata.

Sin embargo, no debe adoptarse como una solución permanente. La buena práctica de administración dicta planificar ventanas de mantenimiento periódicas para la rotación formal de credenciales y la asignación de perfiles con la directiva PASSWORD_LIFE_TIME UNLIMITED exclusivamente a cuentas de servicio de aplicación debidamente auditadas.

Saludos.

jueves, 21 de mayo de 2026

Corregir la fragmentación y reducir el High Water Mark (HWM) con SHRINK SPACE


En la administración de bases de datos Oracle, un escenario común de degradación de rendimiento ocurre cuando una tabla que solía albergar millones de registros sufre un proceso masivo de depuración (DELETE). A pesar de que los datos ya no residen en el disco, las consultas tipo Full Table Scan (FTS) sobre dicha tabla continúan demorando el mismo tiempo o consumiendo una cantidad idéntica de operaciones de E/S (I/O).

¿Por qué sucede esto? La respuesta se encuentra en el High Water Mark (HWM) o la "marca de agua" del segmento. En este artículo analizaremos conceptualmente este comportamiento, construiremos un laboratorio en la versión 19c para simular la fragmentación y demostraremos cómo diagnosticar y compactar el espacio desperdiciado utilizando herramientas nativas.

¿Qué es el High Water Mark?

El HWM es un puntero dentro de la estructura de almacenamiento de Oracle que define el límite hasta donde se han escrito bloques de datos en un segmento.

  • Cuando se realizan operaciones de INSERT, el HWM sube de manera dinámica para asignar nuevos bloques.

  • Cuando se realiza una operación de DELETE, los registros se borran lógicamente y los bloques quedan vacíos, pero el HWM no se reduce.

Dado que un Full Table Scan lee obligatoriamente todos los bloques por debajo del HWM (asumiendo que contienen datos válidos), Oracle terminará leyendo bloques vacíos de manera innecesaria, degradando el rendimiento de los queries y desperdiciando memoria en el Buffer Cache.

Simulación de Fragmentación


Para demostrar este impacto, crearemos una tabla de pruebas, la poblaremos con un volumen considerable de datos, realizaremos una depuración masiva y mediremos el comportamiento de los bloques.
-- Creamos una tabla basada en los objetos del diccionario para simular volumen
CREATE TABLE t_hwm_test AS SELECT rownum as id, a.* FROM all_objects a, (SELECT 1 FROM dual CONNECT BY level <= 10); 

-- Contamos la cantidad de registros creados en la tabla
SELECT COUNT(*) FROM t_hwm_test;

-- Verificamos el tamaño inicial del segmento y bloques asignados 
SELECT blocks, bytes/1024/1024 AS MB FROM user_segments WHERE segment_name = 'T_HWM_TEST';


Procederemos a eliminar el 90% de los registros de la tabla para inducir una fragmentación severa del segmento.

-- Eliminamos la gran mayoría de los registros 
DELETE FROM t_hwm_test WHERE MOD(id, 10) != 0;
COMMIT;

-- Ejecutamos estadísticas para actualizar el diccionario de datos

EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T_HWM_TEST');


Si consultamos las vistas USER_TABLES (datos lógicos) y USER_SEGMENTS (datos físicos), notaremos la discrepancia:

SELECT t.table_name, t.num_rows, t.blocks AS blocks_with_data, s.blocks AS total_allocated_blocks FROM user_tables t JOIN user_segments s ON t.table_name = s.segment_name WHERE t.table_name = 'T_HWM_TEST';

Para no depender exclusivamente de la ejecución de estadísticas de las tablas, podemos utilizar el paquete nativo DBMS_SPACE.UNUSED_SPACE para obtener el estado del HWM en tiempo real.

Ejecutaremos el siguiente bloque de código en nuestra sesión:

DECLARE
    v_total_blocks       NUMBER;
    v_total_bytes        NUMBER;
    v_unused_blocks      NUMBER;
    v_unused_bytes       NUMBER;
    v_last_used_extent_file_id NUMBER;
    v_last_used_extent_block_id NUMBER;
    v_last_used_block    NUMBER;
BEGIN
    DBMS_SPACE.UNUSED_SPACE(
        segment_owner             => USER,
        segment_name              => 'T_HWM_TEST',
        segment_type              => 'TABLE',
        total_blocks              => v_total_blocks,
        total_bytes               => v_total_bytes,
        unused_blocks             => v_unused_blocks,
        unused_bytes              => v_unused_bytes,
        last_used_extent_file_id  => v_last_used_extent_file_id,
        last_used_extent_block_id => v_last_used_extent_block_id,
        last_used_block           => v_last_used_block
    );
    DBMS_OUTPUT.PUT_LINE('Bloques Totales Asignados: ' || v_total_blocks);
    DBMS_OUTPUT.PUT_LINE('Bloques sobre el HWM (Sin usar): ' || v_unused_blocks);
    DBMS_OUTPUT.PUT_LINE('Bloques por debajo del HWM (HWM Actual): ' || (v_total_blocks - v_unused_blocks));
END;
/

Compactación del Segmento con SHRINK SPACE 


A partir de la introducción de los tablespaces con administración automática de espacio de segmentos (ASSM), Oracle provee una instrucción en línea (ONLINE) extremadamente eficiente para reorganizar las filas, liberar el espacio desperdiciado y reajustar el HWM hacia abajo: el comando SHRINK.

El proceso consta de dos fases lógicas ejecutadas internamente por el motor:

  1. Fase de movimiento de filas (Row Movement): Desplaza las filas de la parte superior del segmento hacia los huecos libres en la parte inferior.

  2. Fase de ajuste del HWM: Bloquea brevemente la tabla para bajar el puntero del HWM y liberar el espacio sobrante al tablespace.

Para poder reubicar físicamente los registros y alterar sus ROWID, es obligatorio activar la propiedad ROW MOVEMENT en la tabla:
ALTER TABLE t_hwm_test ENABLE ROW MOVEMENT;

Procedemos a ejecutar el shrink. Este comando liberará el espacio de vuelta al tablespace de forma inmediata.

ALTER TABLE t_hwm_test SHRINK SPACE;


Nota: Si se tratara de una tabla crítica en un entorno productivo de alta concurrencia, podemos ejecutar ALTER TABLE t_hwm_test SHRINK SPACE COMPACT; para realizar solo la fase 1 sin bloquear el HWM, y posteriormente ejecutar el comando completo en una ventana de mantenimiento corta.

Volvemos a recopilar estadísticas y evaluamos nuevamente el estado físico de la tabla en el diccionario de datos.

-- Ejecutamos nuevamente estadísticas sobre la tabla
EXEC
DBMS_STATS.GATHER_TABLE_STATS(USER, 'T_HWM_TEST');

-- Verificamos el total de bloques de la tabla nuevamente 
SELECT t.table_name, t.num_rows, s.blocks AS total_allocated_blocks FROM user_tables t JOIN user_segments s ON t.table_name = s.segment_name WHERE t.table_name = 'T_HWM_TEST';

 


El total_allocated_blocks se redujo drásticamente de 20480 que tenia inicialmente a 2048, alineándose al volumen real actual de la tabla.

Consideraciones

El comando SHRINK SPACE es la herramienta ideal para combatir la fragmentación en bases de datos modernas, sin embargo, como DBAs debemos considerar las siguientes pautas antes de su aplicación en producción:

  1. Índices: A diferencia de un ALTER TABLE MOVE, el comando SHRINK SPACE mantiene los índices de la tabla en estado VALID, ya que actualiza de manera interna las modificaciones de los ROWID. No es necesario un rebuild posterior.

  2. Restricciones: No se puede aplicar SHRINK sobre tablas con índices basados en funciones, vistas materiales con logs de refresco o tablas que contengan columnas de tipo LONG.

  3. Alternativa Tradicional: Si el tablespace no cuenta con ASSM (lo cual es raro en versiones 19c/23ai), la alternativa obligada sigue siendo el clásico ALTER TABLE MOVE seguido de un ALTER INDEX REBUILD.

Comprender el comportamiento del High Water Mark en Oracle 19c es fundamental para evitar diagnósticos erróneos ante caídas de rendimiento repentinas tras procesos de purga masiva. Como DBAs, nuestro rol no solo consiste en liberar espacio en disco, sino en garantizar la eficiencia de las operaciones de E/S.

Saludos.

martes, 5 de mayo de 2026

Configurar y Utilizar Oracle Flashback Technology


Oracle Flashback es una de las herramientas más útiles para un DBA, ya que nos permite recuperar datos o estados de la base de datos sin necesidad de recurrir a backups (RMAN). A diferencia de RMAN, Flashback trabaja con los datos actuales para "deshacer" errores en segundos.

IMPORTANTE: Todos los ejemplos prácticos de esta guía han sido validados y probados en Oracle Database 23ai.

Para utilizar Flashback Database, la base de datos debe estar en modo ARCHIVELOG. Primero verificamos el estado:

SELECT log_mode, flashback_on FROM v$database;


En este caso no se encuentra activo ni el modo archivelog de la base por lo tanto tampoco el modo flashback. Procedemos con la configuración de la Fast Recovery Area (FRA), activamos ambos modos.

--Definir espacio y ruta de la FRA ALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE = 10G; ALTER SYSTEM SET DB_RECOVERY_FILE_DEST = '/opt/oracle/fast_recovery_area';

--Definir retención (ej. 24 horas en minutos) ALTER SYSTEM SET DB_FLASHBACK_RETENTION_TARGET = 1440;

--Activar modos (Requiere modo MOUNT) 
SHUTDOWN IMMEDIATE; 
STARTUP MOUNT; 
ALTER DATABASE ARCHIVELOG; 
ALTER DATABASE FLASHBACK ON; 
ALTER DATABASE OPEN;



No todos los Flashback funcionan igual. Se dividen principalmente por el origen de los datos que utilizan:

Basados en Segmentos de UNDO

Estos dependen del UNDO_TABLESPACE. Si los datos en el undo han sido sobrescritos, la operación fallará.

  • Flashback Query: Permite consultar datos en un tiempo pasado (AS OF TIMESTAMP/SCN).



SELECT last_name, salary FROM hr.employees AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '5' MINUTE) WHERE department_id = 60;


  • Flashback Version Query: Ideal para auditoría, permite ver los cambios de una fila.

--Muestra todas las versiones de una fila en un intervalo
SELECT versions_starttime, versions_operation, salary
FROM hr.employees
VERSIONS BETWEEN TIMESTAMP (SYSTIMESTAMP - INTERVAL '1' HOUR) AND MAXVALUE
WHERE employee_id = 101;
  • Flashback Table: Revierte una tabla completa. (Ojo: requiere Row Movement).

-- Indispensable para evitar error ORA-08189 
ALTER TABLE hr.employees ENABLE ROW MOVEMENT; 

-- Revertir tabla a un punto exacto FLASHBACK TABLE hr.employees TO TIMESTAMP (SYSTIMESTAMP - INTERVAL '10' MINUTE);

Basados en Flashback Logs (FRA)

Dependen de la Fast Recovery Area y capturan cambios a nivel de bloque físico.

  • Flashback Database: Revierte toda la base de datos. Es la opción más drástica y rápida ante errores masivos de despliegue.

-- Si estás en un entorno PDB (CDB/PDB), primero cierra la PDB: 
ALTER PLUGGABLE DATABASE FREEPDB1CLOSE; 

-- Ejecuta el retroceso 
FLASHBACK PLUGGABLE DATABASE FREEPDB1TO TIMESTAMP (SYSTIMESTAMP - INTERVAL '30' MINUTE); 

-- Abre con resetlogs para fijar la nueva línea de tiempo 
ALTER PLUGGABLE DATABASE FREEPDB1OPEN RESETLOGS;





Basados en Metadata (Recycle Bin)

  • Flashback Drop: Recupera tablas borradas con DROP. Oracle simplemente renombra el objeto en el diccionario de datos.

-- Si borraste la tabla por accidente: 
DROP TABLE hr.locations CASCADE CONSTRAINTS; 

-- Recupérala de la "papelera" 
FLASHBACK TABLE hr.locations TO BEFORE DROP;


TIP: A veces, recordar una fecha exacta o un SCN es complicado. Puedes crear un "alias" para el estado actual de tu base de datos antes de realizar cambios importantes.
-- Crear un punto de retorno normal 
CREATE RESTORE POINT antes_del_cambio;

Puedes consultar los puntos guardados

SELECT name, scn, time, guarantee_flashback_database FROM v$restore_point; 

Para regresar al punto especifico creado

-- Para una tabla específica 
FLASHBACK TABLE hr.locations TO RESTORE POINT antes_del_cambio;  

Recuerda que la tecnología Flashback no es solo una funcionalidad de recuperación, sino una estrategia de continuidad de negocio. Mientras que un backup tradicional en RMAN es tu seguro de vida ante un desastre físico o de hardware, Flashback es tu mejor aliado contra el error humano cotidiano.


jueves, 9 de abril de 2026

Resolviendo el error ORA-1652: unable to extend temp segment by 128 in tablespace TEMP


El error ORA-1652 es uno de los incidentes más temidos por los DBAs. La reacción más común suele ser añadir más archivos de datos (Tempfiles), pero la experiencia demuestra que el aumento en el consumo de espacio temporal es debido a un proceso o consulta ineficiente.

Cuando el error ocurre, el espacio en TEMP se libera automáticamente al fallar la sesión, borrando los registros en las vistas de tiempo real. Para investigar, debemos consultar el historial de sesiones activas (ASH) para encontrar el pico máximo de consumo de cada consulta.

SELECT 
    sql_id,
    user_id,
    program,
    round(MAX(temp_space_allocated)/1024/1024/1024,2) AS max_temp_gb,
    MIN(sample_time) AS inicio,
    MAX(sample_time) AS fin
FROM v$active_session_history
WHERE temp_space_allocated > 0
  AND sql_id IS NOT NULL
--Aqui colocamos la fecha y hora relacionada al error ORA-1652  
  AND sample_time BETWEEN TO_TIMESTAMP('08/04/2026 08:00', 'DD/MM/YYYY HH24:MI') 
                      AND TO_TIMESTAMP('08/04/2026 08:30', 'DD/MM/YYYY HH24:MI')
GROUP BY sql_id, user_id, program
ORDER BY max_temp_gb DESC;


En nuestro caso, encontramos que el SQL_ID 85v0ju71vfphg alcanzó un pico de 370 GB. Al revisar el reporte AWR (Automatic Workload Repository), la sección "Top SQL with Top Events" reveló lo siguiente:


  • Evento: direct path write temp
  • Wait Class: User I/O
  • Top Row Source: HASH JOIN / HASH GROUP BY
¿Por qué una consulta necesitaría tanto espacio? Al obtener el plan con DBMS_XPLAN.DISPLAY_AWR, detectamos dos problemas críticos:
  1. MERGE JOIN CARTESIAN: El motor intentó realizar un producto cartesiano (unir cada fila con todas las filas de otra tabla) debido a una condición de unión mal definida con una tabla. Esto multiplicó exponencialmente el set de datos intermedio.

  2. SORT UNIQUE: El uso de UNION (en lugar de UNION ALL) obligó a un ordenamiento masivo para eliminar duplicados de un set de datos que ya estaba inflado por el cartesiano.


Para solucionar esto, el primer paso es auditar la lógica de las uniones (JOINs): asegurar que todas las tablas tengan su predicado de unión correspondiente en el WHERE o en la cláusula ON.

Si la lógica es correcta pero el optimizador sigue eligiendo un cartesiano por un error de estimación en las estadísticas, podemos intervenir usando el hint /*+ NO_CARTESIAN */. Asimismo, evaluamos cambiar UNION por UNION ALL si sabemos que los resultados de ambas consultas son disjuntos o si los duplicados son aceptables.


El ORA-1652 no se resuelve simplemente asignando más disco. Antes de ampliar, identifica el pico (ASH), confirma el evento (AWR) y audita la lógica (Plan de Ejecución). Optimizar el código es, en la gran mayoría de los casos, la forma más eficiente y profesional de resolver este error.

martes, 31 de marzo de 2026

Dimensionamiento de Memoria en Oracle


El rendimiento de una base de datos Oracle no depende de cuánta RAM tengas, sino de cómo la distribuyes. En un entorno de producción, la memoria es un recurso finito y costoso; asignarla en exceso es tan peligroso como quedarse corto, ya que puede inducir problemas de paginación a nivel de OS o enmascarar consultas ineficientes que deberían ser optimizadas en código.

En esta guía aprenderemos a interpretar los Advisors para ajustar la SGA y la PGA utilizando los componentes internos del motor.

Antes de tocar parámetros, debemos entender que es SGA y PGA:

  • SGA (System Global Area): Memoria compartida. Su objetivo es minimizar la I/O física (lectura de disco).

  • PGA (Program Global Area): Memoria privada por proceso. Su objetivo es realizar ordenamientos y uniones "In-Memory".




  • db file sequential read (11.4% del tiempo): Es el tiempo que la base de datos pasa esperando a que el disco le entregue un bloque de datos que no encontró en la memoria. La SGA es demasiado pequeña para el volumen de datos que consultamos. El motor está "trabajando de más" yendo al disco por información que debería estar ya en la RAM.
  • acknowledge over PGA limit: Este es un evento "semáforo". Aparece cuando Oracle detiene un proceso porque ya se alcanzó el límite máximo de memoria RAM permitido. El sistema está asfixiado. Literalmente está "poniendo en cola" a los usuarios porque no hay más memoria disponible para procesar sus consultas. Es la confirmación de que nuestra PGA necesita crecer urgentemente.

Diagnostico SGA (V$SGA_TARGET_ADVICE):
Ejecuta la siguiente consulta:

SELECT sga_size, sga_size_factor, estd_db_time, estd_physical_reads
FROM v$sga_target_advice
ORDER BY sga_size_factor;

Si aumentamos la SGA de 30 GB a 45 GB (Factor 1.5):

  • Lecturas Físicas: Bajan de 170B a 149B (Una reducción del ~12%).
  • Tiempo de DB: Baja de 118M a 114M (Una mejora de apenas el 3.4%).
Necesitamos invertir 15 GB adicionales de RAM para obtener una mejora de velocidad que el usuario final probablemente ni siquiera notará.

Diagnostico PGA(V$PGA_TARGET_ADVICE):
Ejecuta la siguiente consulta:

SELECT pga_target_for_estimate/1024/1024 AS target_mb, 
       pga_target_factor, 
       estd_extra_bytes_rw,
       estd_pga_cache_hit_percentage
FROM v$pga_target_advice;

Si aumentamos la PGA de 10 GB a 18 GB (Factor 1.8):

  • Tráfico en Disco (Extra Bytes RW): Baja de 186 TB a 182 TB. Ahorramos 4 Terabytes de escritura innecesaria en el TEMP.

  • Eficiencia (Cache Hit %): Sube del 91% al 92%.

Es una inversión inteligente. Con solo 8 GB adicionales de RAM, eliminamos el cuello de botella que causa el evento acknowledge over PGA limit y estabilizamos las operaciones pesadas.

Una vez identificado el tamaño óptimo, aplica los cambios. Recuerda que si usas ASMM (Automatic Shared Memory Management), solo ajustas los targets.

Puedes usar esta consulta para verificar:

SELECT 
    name, 
    value/1024/1024 AS mbytes, 
    CASE 
        WHEN name = 'sga_target' AND value > 0 THEN 'ASMM: Gestión Automática de SGA'
        WHEN name = 'pga_aggregate_target' AND value > 0 THEN 'PGA: Gestión Automática de Procesos'
        WHEN name = 'memory_target' AND value > 0 THEN 'AMM: Gestión Total (SGA + PGA)'
        ELSE 'Gestión Manual / Límite Estricto'
    END AS modo_gestion
FROM v$parameter 
WHERE name IN ('sga_target', 'pga_aggregate_target', 'memory_target', 'pga_aggregate_limit');


En este caso solo redimensionaremos la PGA, dado que tenemos mayor beneficio por un bajo costo (8GB de RAM).

-- 1. Subir el Target
ALTER SYSTEM SET pga_aggregate_target = 18G SCOPE=BOTH;
-- 2.  Lo ideal es que el limit sea al menos 2x el target
ALTER SYSTEM SET pga_aggregate_limit = 36G SCOPE=BOTH; 

La PGA es mucho más flexible. Puedes aplicar los cambios y tendrán efecto inmediato, pero cuidado con el límite (limit), debe ser siempre mayor al target.

IMPORTANTE:

No redimensiones sin validar estos tres puntos:

  1. Evitar el Paging: La suma de SGA + PGA + SO nunca debe superar el 80% de la RAM física. Si el SO empieza a usar Swap, el rendimiento de Oracle colapsará.

  2. HugePages (Solo Linux): Si tu SGA es mayor a 8GB, asegúrate de configurar HugePages a nivel de kernel para evitar que el proceso vktm consuma demasiada CPU gestionando tablas de páginas.

  3. Monitoreo Post-Cambio: Tras el ajuste, monitorea V$SQL_WORKAREA_ACTIVE para confirmar que las operaciones pasaron de MULTI-PASS a OPTIMAL.

La mejor optimización de memoria no es comprar más módulos de RAM, sino reducir la necesidad de ella mediante la indexación correcta y el tuning de sentencias SQL.