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;