SEVERE java.sql.SQLRecoverableException: IO Error: Connection reset – Linux system

Después de varios días volviéndonos locos y de sufrir con dos síntomas, por un lado, cuando creábamos una conexión en sqldeveloper aunque le pedíamos que guardara el password no lo hacía y con errores intermitentes de java, con timeout en las conexiones, Descubrimos que hay un problema con los poles de generación número aleatorios en las máquinas virtuales. Esto se puede solucionar instalando y levantando haveged que permite generar de manera más rápida los números random,con esto se acelera la generación de llaves SSL y hace la encriptación más efectiva.

Según Oracle cuando hay una diferencia muy grnade entre el número de estos dos ficheros, siendo mucho menor el segundo:

$ cat /proc/sys/kernel/random/poolsize

$ cat /proc/sys/kernel/random/entropy_avail

Puede haber problemas que se solucionan instalando y levantando havenged.

 

# yum install haveged

# systemctl start haveged

# systemctl enable haveged

REDUNDANCIA PARA VOTING DISK

Si decides almacenar el fichero de voting disk en el mismo diskgroup de ASM que los ficheros de datos, añadir un grupo de fallo puede suponer añadir un montón de espacio y puede que esto suponga un problema. Para solucionar esto, se introduce un nuevo grupo de fallo tipo quorum. Cuando se añade este tipo de grupo, solamente se utiliza para añadir una copia extra de voting dik en ese grupo de fallo, lo cual permite que este disco sea mucho menor al resto que compone el grupo.

Generaríamos el disckgroup de esta manera, siendo FG1 y FG2 del mismo tamaño y FG3 mucho menor ya que solo va almacenar el voting disk.

CREATE DISKGROUP PRUEBA NORMAL REDUNDANCY
FAILGROUP FG1 DISK 'ORCL:PRUEBA01' NAME PRUEBA01
FAILGROUP FG2 DISK 'ORCL: PRUEBA02' NAME PRUEBA02
QUORUM FAILGROUP FG3 DISK 'ORCL: PRUEBA03' NAME PRUEBA03
ATTRIBUTE 'compatible.asm' = '11.2';

ORA-01878: specified field not found in datetime or interval

El problema es que existen datos que queremos convertir con un función de timezone, en el intervalo horario del cambio de hora. Por ejemplo si el cambio de hora es el 27/3 a las 2:00. No podemos tener datos entre las 2:00 y las 2:59. El último tiene que ser a la 1:59 y el siguiente a las 3:00. Ya que ese intervalo de tiempo realmente no existe.

La solución es buscar los datos que se encuentran en ese intervalo con un betwen y actualizarlos a un valor a un valor correcto.

Realmente no es un problema de Oracle es la forma en que se tratan las horas con DST, cuando se modifica el offset , siempre hay una hora en que el tiempo se mueve hacia adelante (= no existe).

http://en.wikipedia.org/wiki/Daylight_saving_time

Hoy vamos a ver un poco del purgado de colas:

Tenemos 73 ordenes en coladas que se intentado procesar en multiples ocasiones y dan error.

select count(*) from EJEMPLOQUEUE_DRM_TAB;
COUNT(*)
----------
 73
select queue,msg_state,count(*) from aq$EJEMPLOQUEUE_TAB; group by queue,msg_state;
QUEUE MSG_STATE COUNT(*)
------------------------------ ---------------- ----------
CDBQUEUE_DRM READY 73

Con esto las purgamos, más detalles sobre este paquete en http://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_aqadm.htm#i1014013

Ejemplo de la sentencia, basandonos en número de repeticiones.

DECLARE
 po_t dbms_aqadm.aq$_purge_options_t;
BEGIN
 dbms_aqadm.purge_queue_table('MMOADSL.EJEMPLOQUEUE_TAB;', 'qtview.RETRY_COUNT > 100' , po_t);
END;
select count(*) from EJEMPLOQUEUE_TAB;
COUNT(*)
----------
 0
 
 
Select Q_NAME, RETRY_COUNT from EJEMPLOQUEUE_TAB;
Q_NAME RETRY_COUNT
------------------------------ -----------
EJEMPLOQUEUE;_DRM 9892
EJEMPLOQUEUE;_DRM 17909
EJEMPLOQUEUE;_DRM 17912
EJEMPLOQUEUE;_DRM 17909
EJEMPLOQUEUE;_DRM 17917
EJEMPLOQUEUE;_DRM 17912
EJEMPLOQUEUE;_DRM 17912
EJEMPLOQUEUE;_DRM 17880
EJEMPLOQUEUE;_DRM 17878
EJEMPLOQUEUE;_DRM 17881
EJEMPLOQUEUE;_DRM 17871
Q_NAME RETRY_COUNT
------------------------------ -----------
EJEMPLOQUEUE;_DRM 17871
EJEMPLOQUEUE;_DRM 17873
EJEMPLOQUEUE;_DRM 17868
EJEMPLOQUEUE;_DRM 17869
EJEMPLOQUEUE;_DRM 17868
EJEMPLOQUEUE;_DRM 16813
EJEMPLOQUEUE;_DRM 16811
EJEMPLOQUEUE;_DRM 16811
EJEMPLOQUEUE;_DRM 15561
EJEMPLOQUEUE;_DRM 15306
EJEMPLOQUEUE;_DRM 15305
Q_NAME RETRY_COUNT
------------------------------ -----------
EJEMPLOQUEUE;_DRM 11617
EJEMPLOQUEUE;_DRM 11617
EJEMPLOQUEUE;_DRM 11617
EJEMPLOQUEUE;_DRM 11434
EJEMPLOQUEUE;_DRM 11428
EJEMPLOQUEUE;_DRM 11429
EJEMPLOQUEUE;_DRM 15350
EJEMPLOQUEUE;_DRM 25662
EJEMPLOQUEUE;_DRM 25666
EJEMPLOQUEUE;_DRM 25652
EJEMPLOQUEUE;_DRM 11918
Q_NAME RETRY_COUNT
------------------------------ -----------
EJEMPLOQUEUE;_DRM 11917
EJEMPLOQUEUE;_DRM 11917
EJEMPLOQUEUE;_DRM 5361
EJEMPLOQUEUE;_DRM 5360
EJEMPLOQUEUE;_DRM 5361
EJEMPLOQUEUE;_DRM 15629
EJEMPLOQUEUE;_DRM 21670
EJEMPLOQUEUE;_DRM 21674
EJEMPLOQUEUE;_DRM 15629
EJEMPLOQUEUE;_DRM 21669
EJEMPLOQUEUE;_DRM 15627
Q_NAME RETRY_COUNT
------------------------------ -----------
EJEMPLOQUEUE;_DRM 15611
EJEMPLOQUEUE;_DRM 15610
EJEMPLOQUEUE;_DRM 15610
EJEMPLOQUEUE;_DRM 8793
EJEMPLOQUEUE;_DRM 8790
EJEMPLOQUEUE;_DRM 8791
EJEMPLOQUEUE;_DRM 1871
EJEMPLOQUEUE;_DRM 25950
EJEMPLOQUEUE;_DRM 25941
EJEMPLOQUEUE;_DRM 25943
EJEMPLOQUEUE;_DRM 1871
Q_NAME RETRY_COUNT
------------------------------ -----------
EJEMPLOQUEUE;_DRM 1872
EJEMPLOQUEUE;_DRM 12769
EJEMPLOQUEUE;_DRM 12769
EJEMPLOQUEUE;_DRM 12768
EJEMPLOQUEUE;_DRM 12769
EJEMPLOQUEUE;_DRM 8795
EJEMPLOQUEUE;_DRM 8798
EJEMPLOQUEUE;_DRM 8794
EJEMPLOQUEUE;_DRM 9906
EJEMPLOQUEUE;_DRM 19360
EJEMPLOQUEUE;_DRM 19358
Q_NAME RETRY_COUNT
------------------------------ -----------
EJEMPLOQUEUE;_DRM 19353
EJEMPLOQUEUE;_DRM 15568
EJEMPLOQUEUE;_DRM 21100
EJEMPLOQUEUE;_DRM 21097
EJEMPLOQUEUE;_DRM 2787
EJEMPLOQUEUE;_DRM 2787
EJEMPLOQUEUE;_DRM 2785

Cambiar next_run_date en DBMS_SCHEDULER

Este atributo no se puede cambiar directamente, lo que se tiene que hacer es cambiar el start_date

exec dbms_scheduler.disable (‘<usuario>.<nombre_job>’);

declare
v_new_next_date timestamp with time zone;
begin
select to_timestamp_tz(to_char(trunc(sysdate),’DD-MON-YYYY’) || ‘ 12:05:00 PM +00:00′) into v_new_next_date
from dual;
dbms_scheduler.set_attribute(name=>'<usuario>.<nombre_job>’, attribute=>’START_DATE’,value=>v_new_next_date);
end;
/
EXEC dbms_scheduler.enable ( ‘<usuario>.<nombre_job>’);

/

Version Count

Qué son los version count?

Lo primero hay que hay que recordar es todas las SQL son compartidas implícitamente. Cuando una sentencia SQL se ejecuta en la base de datos, el RDBMS crea un valor hash para el texto de la sentencia y ese has ayuda al RDMBMS a encontrar fácilmente el SQL si ya esta en la shared pool.

Por ejemplo: :- ‘select count(*) from emp’ obtiene el valor 8086390035

Se crea un cursor padre para la sql y un solo cursos hijo. No importa que la sentencia SQL nunca se comparta. Siempre se crea un padre y un hijo, la forma más sencilla es pensar que el cursor padre representa el valor hash y el cursor hijo representa los metadatos para esa sql.

Los metadatos serian toda la información necesaria para que esa select se ejecute. Por ejemplo en la sentencia que hemos puesto la tabla EMP  es de Scott. Tendríamos que pensar que el cursor padre se puede compartir pero el hijo depende de los permisos que tenga el usuario.  Por ejemplo para la sentencia dada los metadatos que están en el cursor hijo no serían iguales si los usuarios son diferentes. Con lo cual si el usuario pepito ejecutara select count(*) from emp, tendría que crear un nuevo cursor hijo con sus metadatos, con las validaciones necesarias para la ejecución de la select.
Cuando hay demasiadas versiones innecesarias de un mismo cursor, cada vez que el cursor es ejecutado el motor tiene que revisar entre todos los hijos para ver cuál necesita, esto supone un gasto de CPU, que se podría estar utilizando en otra cosa.

Oracle tiene un script que te permite averiguar porque no se está reutilizando la select. Se ejecuta como sys y te crea algún que otro objeto.

El script esta en metalink

Document 438755.1 High SQL Version Counts – Script to determine reason(s)

Pero aquí pongo una select que hace algo similar sin tener que crear nada. Mostrará todas las razones por la cuan no se está utilizando, luego es necesario buscar la explicación a estas razones. Os paso el enlace de dónde encontrar esa explicación.

https://docs.oracle.com/cd/E11882_01/server.112/e40402/dynviews_3059.htm

En este ejemplo buscamos por un sql_id concreto, pero entre comentario esta como buscar por los que tiene un determinado numero de cursores.

set linesize 200
select version_count,address,hash_value,parsing_schema_name,reason,sql_text from 
(select
address,''
||decode(max(    UNBOUND_CURSOR    ),'Y', '     UNBOUND_CURSOR    ')
||decode(max(    SQL_TYPE_MISMATCH    ),'Y', '     SQL_TYPE_MISMATCH    ')
||decode(max(    OPTIMIZER_MISMATCH    ),'Y', '     OPTIMIZER_MISMATCH    ')
||decode(max(    OUTLINE_MISMATCH    ),'Y', '     OUTLINE_MISMATCH    ')
||decode(max(    STATS_ROW_MISMATCH    ),'Y', '     STATS_ROW_MISMATCH    ')
||decode(max(    LITERAL_MISMATCH    ),'Y', '     LITERAL_MISMATCH    ')
||decode(max(    FORCE_HARD_PARSE    ),'Y', '     FORCE_HARD_PARSE    ')
||decode(max(    EXPLAIN_PLAN_CURSOR    ),'Y', '     EXPLAIN_PLAN_CURSOR    ')
||decode(max(    BUFFERED_DML_MISMATCH    ),'Y', '     BUFFERED_DML_MISMATCH    ')
||decode(max(    PDML_ENV_MISMATCH    ),'Y', '     PDML_ENV_MISMATCH    ')
||decode(max(    INST_DRTLD_MISMATCH    ),'Y', '     INST_DRTLD_MISMATCH    ')
||decode(max(    SLAVE_QC_MISMATCH    ),'Y', '     SLAVE_QC_MISMATCH    ')
||decode(max(    TYPECHECK_MISMATCH    ),'Y', '     TYPECHECK_MISMATCH    ')
||decode(max(    AUTH_CHECK_MISMATCH    ),'Y', '     AUTH_CHECK_MISMATCH    ')
||decode(max(    BIND_MISMATCH    ),'Y', '     BIND_MISMATCH    ')
||decode(max(    DESCRIBE_MISMATCH    ),'Y', '     DESCRIBE_MISMATCH    ')
||decode(max(    LANGUAGE_MISMATCH    ),'Y', '     LANGUAGE_MISMATCH    ')
||decode(max(    TRANSLATION_MISMATCH    ),'Y', '     TRANSLATION_MISMATCH    ')
||decode(max(    BIND_EQUIV_FAILURE    ),'Y', '     BIND_EQUIV_FAILURE    ')
||decode(max(    INSUFF_PRIVS    ),'Y', '     INSUFF_PRIVS    ')
||decode(max(    INSUFF_PRIVS_REM    ),'Y', '     INSUFF_PRIVS_REM    ')
||decode(max(    REMOTE_TRANS_MISMATCH    ),'Y', '     REMOTE_TRANS_MISMATCH    ')
||decode(max(    LOGMINER_SESSION_MISMATCH    ),'Y', '     LOGMINER_SESSION_MISMATCH    ')
||decode(max(    INCOMP_LTRL_MISMATCH    ),'Y', '     INCOMP_LTRL_MISMATCH    ')
||decode(max(    OVERLAP_TIME_MISMATCH    ),'Y', '     OVERLAP_TIME_MISMATCH    ')
||decode(max(    EDITION_MISMATCH    ),'Y', '     EDITION_MISMATCH    ')
||decode(max(    MV_QUERY_GEN_MISMATCH    ),'Y', '     MV_QUERY_GEN_MISMATCH    ')
||decode(max(    USER_BIND_PEEK_MISMATCH    ),'Y', '     USER_BIND_PEEK_MISMATCH    ')
||decode(max(    TYPCHK_DEP_MISMATCH    ),'Y', '     TYPCHK_DEP_MISMATCH    ')
||decode(max(    NO_TRIGGER_MISMATCH    ),'Y', '     NO_TRIGGER_MISMATCH    ')
||decode(max(    FLASHBACK_CURSOR    ),'Y', '     FLASHBACK_CURSOR    ')
||decode(max(    ANYDATA_TRANSFORMATION    ),'Y', '     ANYDATA_TRANSFORMATION    ')
||decode(max(    PDDL_ENV_MISMATCH    ),'Y', '     PDDL_ENV_MISMATCH    ')
||decode(max(    TOP_LEVEL_RPI_CURSOR    ),'Y', '     TOP_LEVEL_RPI_CURSOR    ')
||decode(max(    DIFFERENT_LONG_LENGTH    ),'Y', '     DIFFERENT_LONG_LENGTH    ')
||decode(max(    LOGICAL_STANDBY_APPLY    ),'Y', '     LOGICAL_STANDBY_APPLY    ')
||decode(max(    DIFF_CALL_DURN    ),'Y', '     DIFF_CALL_DURN    ')
||decode(max(    BIND_UACS_DIFF    ),'Y', '     BIND_UACS_DIFF    ')
||decode(max(    PLSQL_CMP_SWITCHS_DIFF    ),'Y', '     PLSQL_CMP_SWITCHS_DIFF    ')
||decode(max(    CURSOR_PARTS_MISMATCH    ),'Y', '     CURSOR_PARTS_MISMATCH    ')
||decode(max(    STB_OBJECT_MISMATCH    ),'Y', '     STB_OBJECT_MISMATCH    ')
||decode(max(    CROSSEDITION_TRIGGER_MISMATCH    ),'Y', '     CROSSEDITION_TRIGGER_MISMATCH    ')
||decode(max(    PQ_SLAVE_MISMATCH    ),'Y', '     PQ_SLAVE_MISMATCH    ')
||decode(max(    TOP_LEVEL_DDL_MISMATCH    ),'Y', '     TOP_LEVEL_DDL_MISMATCH    ')
||decode(max(    MULTI_PX_MISMATCH    ),'Y', '     MULTI_PX_MISMATCH    ')
||decode(max(    BIND_PEEKED_PQ_MISMATCH    ),'Y', '     BIND_PEEKED_PQ_MISMATCH    ')
||decode(max(    MV_REWRITE_MISMATCH    ),'Y', '     MV_REWRITE_MISMATCH    ')
||decode(max(    ROLL_INVALID_MISMATCH    ),'Y', '     ROLL_INVALID_MISMATCH    ')
||decode(max(    OPTIMIZER_MODE_MISMATCH    ),'Y', '     OPTIMIZER_MODE_MISMATCH    ')
||decode(max(    PX_MISMATCH    ),'Y', '     PX_MISMATCH    ')
||decode(max(    MV_STALEOBJ_MISMATCH    ),'Y', '     MV_STALEOBJ_MISMATCH    ')
||decode(max(    FLASHBACK_TABLE_MISMATCH    ),'Y', '     FLASHBACK_TABLE_MISMATCH    ')
||decode(max(    LITREP_COMP_MISMATCH    ),'Y', '     LITREP_COMP_MISMATCH    ')
||decode(max(    PLSQL_DEBUG    ),'Y', '     PLSQL_DEBUG    ')
||decode(max(    LOAD_OPTIMIZER_STATS    ),'Y', '     LOAD_OPTIMIZER_STATS    ')
||decode(max(    ACL_MISMATCH    ),'Y', '     ACL_MISMATCH    ')
||decode(max(    FLASHBACK_ARCHIVE_MISMATCH    ),'Y', '     FLASHBACK_ARCHIVE_MISMATCH    ')
||decode(max(    LOCK_USER_SCHEMA_FAILED    ),'Y', '     LOCK_USER_SCHEMA_FAILED    ')
||decode(max(    REMOTE_MAPPING_MISMATCH    ),'Y', '     REMOTE_MAPPING_MISMATCH    ')
||decode(max(    LOAD_RUNTIME_HEAP_FAILED    ),'Y', '    LOAD_RUNTIME_HEAP_FAILED    ')
||decode(max(    HASH_MATCH_FAILED    ),'Y', '   HASH_MATCH_FAILED    ')
||decode(max(    PURGED_CURSOR    ),'Y', '   PURGED_CURSOR    ')
||decode(max(    BIND_LENGTH_UPGRADEABLE    ),'Y', '   BIND_LENGTH_UPGRADEABLE    ')
reason
from gv$sql_shared_cursor
group by
address) join gv$sqlarea using(address) where SQL_ID = '<id>'  /* version_count>5 */
order by version_count desc,address;