Oracle 19c

Mostrando las entradas con la etiqueta Oracle 19c. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Oracle 19c. Mostrar todas las entradas

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, 10 de marzo de 2026

Reubicación de la Auditoría Estándar (AUD$) en Oracle


En entornos de producción, es común que las áreas de Seguridad de la Información exijan auditar las acciones de los usuarios. El objetivo es claro: garantizar el control y la trazabilidad ante incidentes que puedan impactar negativamente al negocio. Sin embargo, habilitar esta auditoría es solo la mitad del trabajo; la otra mitad es gestionarla correctamente para no comprometer la disponibilidad de la base de datos.

Uno de los errores más peligrosos en configuraciones por defecto es permitir que la tabla de auditoría estándar (AUD$) crezca dentro de los tablespaces del sistema (SYSTEM o SYSAUX). Si esta crece sin control, corres el riesgo de fragmentar el diccionario de datos o colapsar la instancia por falta de espacio.


Si la tabla AUD$ crece sin control, corres el riesgo de fragmentar el diccionario de datos o, peor aún, colapsar la instancia por falta de espacio. En este post, te mostraré la forma correcta y soportada de mover la auditoría a un tablespace dedicado utilizando el paquete DBMS_AUDIT_MGMT.


Importante: Este procedimiento es válido únicamente para la Auditoría Tradicional. Si tu base de datos tiene habilitado Unified Auditing (lo cual es el estándar en 19c), los registros se almacenan en el esquema AUDSYS y la gestión del espacio se realiza exclusivamente mediante el paquete DBMS_AUDIT_MGMT.

Lo primero es crear un tablespace exclusivo. Es una buena práctica habilitar el AUTOEXTEND con un límite razonable para evitar sorpresas.

CREATE TABLESPACE TBS_AUDIT DATAFILE '+DATA' SIZE 2G AUTOEXTEND ON NEXT 512M MAXSIZE 30G;

Antes de realizar cambios, debemos validar la ubicación actual de la tabla AUD$:

SELECT table_name, tablespace_name 
FROM dba_tables 
WHERE table_name IN ('AUD$');


Para realizar el movimiento de forma segura y soportada, utilizaremos el procedimiento SET_AUDIT_TRAIL_LOCATION. Este se encarga de mover tanto la tabla como sus índices (LOBs incluidos) sin afectar el diccionario de datos.
BEGIN
DBMS_AUDIT_MGMT.SET_AUDIT_TRAIL_LOCATION(audit_trail_type => DBMS_AUDIT_MGMT.AUDIT_TRAIL_AUD_STD,
audit_trail_location_value => 'TBS_AUDIT'); 
END;
/
Una vez ejecutado, verifica que el cambio se haya aplicado correctamente consultando nuevamente el diccionario de datos.

SELECT table_name, tablespace_name FROM dba_tables WHERE table_name IN ('AUD$');


Mover la auditoría no es solo una tarea de mantenimiento, es una medida de seguridad operativa. Al separar los logs de auditoría del tablespace SYSTEM, proteges la salud de tu diccionario de datos y facilitas la gestión de purgas futuras.

Nota: Este procedimiento fue probado en la versión 12c de Oracle.

Saludos.

viernes, 27 de febrero de 2026

De 12c a 19c: Guía de Migración y Upgrade mediante RMAN (Método Manual)


A todos nos ha pasado que, dentro de las tareas que desempeña un DBA, está la de "actualizar la versión del motor" a una superior, ya sea por temas de obsolescencia, bugs, fin de soporte, etc.

Recientemente, me tocó actualizar y migrar hacia otro servidor una de las bases de datos que administro. Esta decisión no fue opcional: la versión 12c ya no cuenta con soporte oficial de Oracle para parches de seguridad y el sistema operativo del servidor original presentaba vulnerabilidades críticas debido a su antigüedad.

Lo primero que realicé fue verificar el modo de operación de la base de datos. Una de las estrategias clave para mantener el mínimo de indisponibilidad (downtime) es trabajar con la base de datos en modo ARCHIVELOG.

¿Por qué es esto vital? Porque nos permite definir un punto de corte claro y realizar el cambio (switchover) de forma controlada. Al tener los archivelogs activos, podemos asegurar que no se pierda ni una sola transacción durante el proceso de movimiento entre servidores.

Luego de ello, me enfoqué en generar el respaldo de la base de datos desde rman, dejo por aquí el código que utilicé, deben reemplaza nombre_de_tu_base por el nombre de la base de datos:


RESPALDO:

         backup_database.sh

export ORACLE_SID=nombre_de_tu_base
export ORACLE_BASE=/oracle/oracle/app/oracle
export ORACLE_HOME=$ORACLE_BASE/product/12.2.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'
rman target / log=/backups/RMAN/backup_nombre_de_tu_base.log << EOF
run
{
CONFIGURE DEVICE TYPE DISK BACKUP TYPE TO COMPRESSED BACKUPSET;
CONFIGURE CHANNEL DEVICE TYPE DISK MAXPIECESIZE 4G;
allocate channel c1 device type disk;
allocate channel c2 device type disk;
allocate channel c3 device type disk;
allocate channel c4 device type disk;
backup spfile format '/backups/RMAN/nombre_de_tu_base_spfile_%u';
backup filesperset=4 database format '/backups/RMAN/nombre_de_tu_base_datafiles_%U';
backup current controlfile format '/backups/RMAN/nombre_de_tu_base_control-%U';
backup archivelog all format '/backups/RMAN/nombre_de_tu_base_arc_%U';
release channel c1;
release channel c2;
release channel c3;
release channel c4;
}
exit;
EOF

Ejecutamos el proceso de respaldo con el comando:

nohup sh backup_database.sh &

Un vez finalizado el proceso de respaldo, en el directorio encontraremos archivos nombrados como: nombre_de_tu_base_spfile, nombre_de_tu_base_datafiles, nombre_de_tu_base_control, nombre_de_tu_base_arc.


Procedemos a ejecutar la restauración de la base en un home 19c con el backup generado en la versión 12c.


RESTAURACIÓN:

Creamos un init.ora para nuestra base de datos en el nuevo servidor en la ruta: /oracle/oracle/app/oracle/product/19.0.0/db_home/dbs

            init.ora

*.audit_file_dest='/oracle/oracle/app/oracle/oracle_base/admin/nombre_de_tu_base/adump'
*.audit_trail='db'
*.control_files='+GDATA','+GFRA'
*.db_block_size=8192
*.db_name='nombre_de_tu_base'
*.db_unique_name='nombre_de_tu_base'
*.compatible='12.2.0'
*.db_files=2000
*.db_recovery_file_dest='+GFRA'
*.db_recovery_file_dest_size=2000g
*.diagnostic_dest='/oracle/oracle/app/oracle/oracle_base'
*.dispatchers='(PROTOCOL=TCP) (SERVICE=dbgenXDB)'
*.nls_language='AMERICAN'
*.nls_territory='AMERICA'
*.open_cursors=300
*.pga_aggregate_target=15g
*.processes=2600
*.remote_login_passwordfile='EXCLUSIVE'
*.sga_target=50g
*.undo_tablespace='UNDOTBS1'

IMPORTANTE: Asegúrate de que el parámetro compatible en tu init.ora sea exactamente el mismo que tenía la base de datos origen (ej. 12.2.0).  

Si no existe, procedemos a crear la carpeta adump:
mkdir /oracle/oracle/app/oracle/oracle_base/admin/nombre_de_tu_base/adump -p

Iniciamos la base de datos en modo no mount:

STARTUP NOMOUNT PFILE='/oracle/oracle/app/oracle/product/19.0.0/db_home/dbs/initdnombre_de_tu_base.ora';

 Restauramos los control file, usualmente el archivo contiene la palabra *control*:

rman target /
restore controlfile from '/backups/RMAN/nombre_de_tu_base_control-gk4b2vc8_1_1';

El paso anterior nos dará la ruta donde se han restaurado los control file, las cuales deberemos copiar y reemplazar en nuestro init.ora

output file name=+GDATA/NOMBRE_DE_TU_BASE/CONTROLFILE/current.261.1219619035
output file name=+GFRA/NOMBRE_DE_TU_BASE/CONTROLFILE/current.508.1219619037 

 Apagamos la base de datos para modificar el init.ora

shutdown immediate;

Modificamos en el init.ora el apartado de *.control_files con las rutas del anterio paso.

vi init.ora

*.control_files='+GDATA/nombre_de_tu_base/CONTROLFILE/current.258.1217774787','+GFRA/nombre_de_tu_base/CONTROLFILE/current.256.1217774787'

Iniciamos la base de datos en modo mount.

STARTUP MOUNT PFILE='/oracle/oracle/app/oracle/product/19.0.0/db_home/dbs/init.ora';

Creamos nuestro SPFILE a partir de nuestro PFILE (init.ora).

 CREATE SPFILE FROM PFILE='/oracle/oracle/app/oracle/product/19.0.0/db_home/dbs/init.ora';

Catalogamos los datafiles desde RMAN.

rman target /
CATALOG START WITH '/backups/RMAN/';
yes

 Sincronizamos el catalogo de respaldos y eliminamos los que se encuentren en estado expirado.

crosscheck backup;
delete noprompt expired backup; 

Sincronizamos el catalogo de archivelogs y eliminamos los que se encuentren en estado expirado.

crosscheck archivelog all;
delete noprompt expired archivelog all;

 Creamos el script bash para restaura la base de datos.

        restore_database.sh

export ORACLE_SID=nombre_de_tu_base
export ORACLE_BASE=/oracle/oracle/app/oracle
export ORACLE_HOME=$ORACLE_BASE/product/19.0.0/db_home
export PATH=$ORACLE_HOME/bin:$PATH
export NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'
rman target / log=/oracle/oracle/restore_database.log <<EOF
run
{
allocate channel c1 device type disk;
allocate channel c2 device type disk;
allocate channel c3 device type disk;
allocate channel c4 device type disk;
allocate channel c5 device type disk;
allocate channel c6 device type disk;
allocate channel c7 device type disk;
allocate channel c8 device type disk;
set newname for database to '+GDATA';
restore database;
switch datafile all;
recover database;
release channel c1;
release channel c2;
release channel c3;
release channel c4;
release channel c5;
release channel c6;
release channel c7;
release channel c8;
}
exit;
EOF 

Ejecutamos el proceso de restauración con el comando:

nohup sh restore_database.sh &

Catalogamos los archivelogs y procedemos a aplicar para terminar de sincronizar la base de datos.

rman target /
CATALOG START WITH '/backups/RMAN/ARCHIVELOG';
yes
recover database;
Apagamos la base de datos y la iniciamos en modo UPGRADE para proceder con la actualización.
sqlplus / as sysdba
SHUTDOWN IMMEDIATE;
STARTUP UPGRADE;
exit

IMPORTANTE: No intentes un ALTER DATABASE OPEN RESETLOGS convencional, ya que fallará debido a la diferencia de versiones del diccionario.

ACTUALIZACIÓN:

Con esto podemos iniciar el upgrade de la base de datos, es necesario dar permisos de ejecución al utilitario de upgrade.

chmod u+x $ORACLE_HOME/rdbms/admin/catctl.pl

 Antes de realizar el upgrade, necesitas saber si tu base de datos cumple con los requisitos mínimos. Oracle proporciona un archivo Java llamado preupgrade.jar

$ORACLE_HOME_19c/jdk/bin/java -jar $ORACLE_HOME_19c/rdbms/admin/preupgrade.jar terminal

Ejecutar el utilitario de upgrade database desde linux y guardar la ejecución en un log. Podemos colocarle 4 hilos para que el proceso lo haga en menos tiempo, depende mucho de la capacidad computacional de tu servidor. 

        Con hilos:

nohup $ORACLE_HOME/rdbms/admin/catctl.pl -n 4 $ORACLE_HOME/rdbms/admin/catupgrd.sql > upgrade.log &

         Sin hilos:

nohup $ORACLE_HOME/rdbms/admin/catctl.pl $ORACLE_HOME/rdbms/admin/catupgrd.sql > upgrade.log &



Iniciamos la base de datos, dado que luego de la actualización se queda en estado shutdown.

sqlplus / as sysdba
startup;

Compilamos los objetos inválidos que desde SQLPlus tras la actualización.

@$ORACLE_HOME/rdbms/admin/utlrp.sql

 Ejecutamos la actualización del diccionario desde SQLPlus.

EXEC DBMS_STATS.GATHER_DICTIONARY_STATS;

Verificamos el estado final del registro de componentes para asegurarnos que todo quede en estado VALIDO.

COLUMN comp_name FORMAT A40
COLUMN version FORMAT A15
SELECT comp_name, version, status FROM dba_registry;

Cambiamos la compatibilidad a versión 19.0.0.0.0 para aprovechar todas la nuevas funciones que trae esta nueva versión.
ALTER SYSTEM SET compatible = '19.0.0.0.0' SCOPE=SPFILE;

IMPORTANTE: Cambia la compatibilidad a 19.0.0 una vez que el upgrade del diccionario haya finalizado con éxito. Este es el ÚLTIMO paso de todo el proceso.

Reiniciamos la base de datos para que tome efecto el cambio de la compatibilidad.

sqlplus / as sysdba
shutdown immediate;
startup;

Migrar y actualizar una base de datos de producción es siempre un reto que pone a prueba nuestra planificación. Aunque el método manual que hemos visto hoy nos da un control total y un entendimiento profundo de lo que sucede, siempre recomiendo automatizar estos pasos en entornos extensos utilizando la herramienta AutoUpgrade de Oracle.

Saludos,

Luis Felipe.