Troubleshooting

Mostrando las entradas con la etiqueta Troubleshooting. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Troubleshooting. 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.

miércoles, 1 de julio de 2026

El valor de los Backups Incrementales ante un borrado accidental de Archivelogs


Durante los procesos de migración de bases de datos Oracle, la gestión del espacio en la Flash Recovery Area (FRA) suele volverse crítica debido a la alta generación de Archive Logs. En escenarios de alta presión, es común recurrir a comandos manuales de depuración. Sin embargo, el uso descuidado de la cláusula FORCE puede derivar en un escenario catastrófico.

En este artículo analizaremos cómo un borrado forzado de secuencias de Archive Logs afectó un respaldo de migración en ejecución, y cómo la ejecución de un Backup Incremental Level 1 actuó como salvavidas para mantener la disponibilidad de los datos.

El objetivo era generar un respaldo completo para mover la base de datos hacia un nuevo servidor. Debido al alto volumen de transacciones, la FRA comenzó a quedarse sin espacio. Para mitigar esto, se procedió a respaldar los logs directamente hacia un Filesystem alterno para liberar espacio local.

Para acelerar la depuración, se optó por eliminar los Archive Logs basándose en rangos de secuencias (sequence) en lugar de la cláusula habitual por tiempo (BEFORE 'SYSDATE'), aplicando además el parámetro FORCE:

RMAN> DELETE FORCE ARCHIVELOG FROM SEQUENCE 12345 UNTIL SEQUENCE 12355;


⚠️ El Peligro del Modificador FORCE: > El parámetro FORCE de RMAN ejecuta un borrado físico e ignora si los archivos están catalogados correctamente o si residen en múltiples destinos. Al ejecutarlo, RMAN no solo eliminó las secuencias de la FRA, sino que también barrió con las copias de esos mismos Archive Logs que ya se habían respaldado en la ruta del Filesystem destinada a la migración.

Dado que en ese instante se estaba ejecutando el Backup Full (Level 0) base para la migración, la pérdida de estos Archive Logs comprometía la consistencia del respaldo para el posterior RESTORE y RECOVER en el destino. La ventana de mantenimiento parecía perdida.

Originalmente, la estrategia no contemplaba el uso de respaldos incrementales. Sin embargo, ante la crisis, se optó por una solución alternativa basada en la arquitectura de RMAN:

  • Archive Logs: Registran de manera lineal y cronológica los cambios vectoriales aplicados en la base de datos.

  • Backup Incremental Level 1: Captura el estado final de los bloques de datos que sufrieron modificaciones desde el último Level 0.

Para salvar la situación, inmediatamente después de que finalizó el Backup Full, se lanzó de manera manual un Backup Incremental:

RMAN>BACKUP INCREMENTAL LEVEL 1 DATABASE FORMAT '/ruta_de_backup/db_inc_%u';

Al ejecutarse en ese instante, el Level 1 escaneó los datafiles y capturó en un conjunto de respaldos consolidado los bloques que habían cambiado. De esta manera, los cambios atrapados en la brecha de los Archive Logs destruidos quedaron asegurados directamente a nivel de bloques de datos.


Al realizar la restauración en el nuevo servidor, la ausencia de las secuencias de Archive Logs eliminadas por error no detuvo el proceso.
RMAN> RESTORE DATABASE;
RMAN> RECOVER DATABASE;

Durante el paso de RECOVER, RMAN detectó la existencia del Backup Incremental Level 1. En lugar de detenerse inmediatamente solicitando las secuencias perdidas, RMAN aplicó directamente los bloques modificados del archivo incremental sobre el Backup Level 0 restaurado.

Esto consolidó los cambios pendientes directamente en los datafiles, permitiendo alcanzar la consistencia requerida para abrir la base de datos de manera segura:

SQL> ALTER DATABASE OPEN RESETLOGS;

Este escenario demuestra que el Backup Incremental Level 1 es una excelente herramienta de contingencia para mitigar rupturas en la cadena de redo histórica, reduciendo drásticamente el RTO al consolidar cambios directamente a nivel de bloques. Sin embargo, para salvaguardar la integridad de la estrategia de recuperación, se debe desterrar el uso reactivo de DELETE FORCE para liberar espacio en la FRA durante operaciones en caliente, ya que RMAN puede eliminar copias válidas en otros destinos activos. En su lugar, la buena práctica exige dimensionar correctamente la FRA antes de la migración, priorizar comandos de cambio de catálogo (CROSSCHECK y DELETE EXPIRED) o reubicar temporalmente los destinos de los logs (LOG_ARCHIVE_DEST_n) hacia un storage externo sin romper la consistencia del respaldo base.

Saludos.


miércoles, 13 de mayo de 2026

Evento enq: JQ - contention ¿Por qué se detienen mis Jobs?


Recientemente, me encontré con un escenario donde los procesos de Job Queue de una base de datos Oracle parecían no avanzar. Al revisar las vistas de rendimiento, identifiqué una espera prolongada en el evento enq: JQ - contention

Para entender el problema, primero debemos recordar cómo gestiona Oracle los jobs. A partir de Oracle 11g y 12c, la arquitectura de Oracle Scheduler separa la programación de la ejecución real mediante varios procesos de fondo:

  • CJQ0 (Job Queue Coordinator): Es el director de orquesta. Lee la tabla de jobs, determina cuál debe ejecutarse y levanta procesos esclavos para realizar el trabajo.

  • Jnnn / Wnnn (Job/Worker Slaves): Son los procesos que ejecutan el código PL/SQL del job.

El Enqueue JQ es un bloqueo de nivel de instancia utilizado para serializar el control de los trabajos. Oracle lo usa para asegurar que un job no sea ejecutado por dos procesos a la vez y para gestionar la creación/terminación de los procesos esclavos.

Cuando vemos el evento enq: JQ - contention, significa que hay una fila de procesos esperando por ese "permiso". Esto suele ocurrir por saturación del coordinador, límites bajos en JOB_QUEUE_PROCESSES o jobs "zombies" que mantienen el bloqueo sin liberar el recurso.

Al ejecutar una consulta a v$session para monitorear los procesos tipo Job (J001), observamos lo siguiente:

SELECT sid, serial#, event, p1, p2, p3, seconds_in_wait FROM v$session WHERE program LIKE '%(J001)%';


Observen la columna SECONDS_IN_WAIT. El proceso lleva más de 12 horas esperando. El valor de P1 (1246822406) traducido a ASCII corresponde precisamente a 'JQ'.

Podemos obtener el valor de P1 traducido a ASCII, con el siguiente query:

SELECT chr(bitand(1246822406,-16777216)/16777216)|| chr(bitand(1246822406,16711680)/65536) AS Enqueue_Type FROM dual;

Para identificar el SPID a nivel de sistema operativo:

SELECT s.sid, p.spid, s.program, s.event FROM v$session s JOIN v$process p ON s.paddr = p.addr WHERE s.program LIKE '%(J001)%';


 En este escenario, al revisar otros procesos esclavos (Workers W...), detectamos sesiones con un LAST_CALL_ET muy alto, lo que indica que están ejecutando tareas que se quedaron colgadas o son ineficientes:

 SELECT p.spid, s.username, s.program, s.last_call_et FROM v$session s JOIN v$process p ON s.paddr = p.addr WHERE s.sid = 4170;



Si la contención es crítica y los jobs están paralizados, la solución más efectiva es "resetear" el coordinador de jobs:

  1. Verificamos el valor actual del parámetro job_queue_processes.

    sqlplus / as sysdba
    SHOW PARAMETER "job_queue_processes";

     

  2. Establecemos el parámetro a cero.

    ALTER SYSTEM SET job_queue_processes=0;

  3. Si existen procesos a nivel de OS que no mueren, identificarlos por su SPID y terminarlos.

  4. Volvemos al valor original, en este caso teníamos lo establecido en 2000.

    ALTER SYSTEM SET job_queue_processes=2000;

Esto obliga al CJQ0 a reiniciarse y liberar los enqueues persistentes.

Como hemos visto, el evento enq: JQ - contention es una señal clara de que el motor de jobs está saturado o bloqueado por un proceso ineficiente. En entornos críticos, especialmente en RAC, no basta con aumentar el número de procesos; es fundamental monitorear el LAST_CALL_ET de los workers para identificar tareas "zombies" que secuestran al coordinador. Realizar un reseteo controlado de la cola de trabajos suele ser la solución más efectiva para normalizar el servicio sin afectar al resto de las instancias del cluster.