---------------------------------------------------------------------------------------- -- -- File name: cs_mark_sql_hot.sql -- -- Purpose: Use DBMS_SHARED_POOL.markhot to reduce contention during high concurency hard parse -- -- Author: Carlos Sierra -- -- Version: 2021/11/05 -- -- Usage: Execute connected to PDB. -- -- Enter SQL_ID when requested. -- -- Example: $ sqlplus / as sysdba -- SQL> @cs_mark_sql_hot.sql -- -- Notes: Developed and tested on 19c -- -- https://jonathanlewis.wordpress.com/2017/10/02/markhot/ -- -- When a statement (through its “full_hash_value”) is marked as hot -- an extra value visible as the property column in v$db_object_cache -- is set to a value that seems to be dependent on the process id of the -- session attempting to execute the statement, and this value is used as -- an extra component in calculating a new full_hash_value (which leads -- to a new hash_value and sql_id). -- With a different full_hash_value the same text generates a new parent -- cursor which is (probably) going to be associated with a new library -- cache hash bucket and latch. -- The property value for the original parent cursor is set to “HOT”, -- and the extra copies become “HOTCOPY1”, “HOTCOPY2” and so on. -- Interestingly once an object is marked as HOT and the first HOTCOPYn -- has appeared the original version may disappear from v$sql while still -- existing in v$db_object_cache. -- --------------------------------------------------------------------------------------- -- @@cs_internal/cs_primary.sql @@cs_internal/cs_cdb_warn.sql @@cs_internal/cs_set.sql @@cs_internal/cs_def.sql @@cs_internal/cs_file_prefix.sql -- DEF cs_script_name = 'cs_mark_sql_hot'; -- PRO PRO 1. Selective SQL Text Substring: (e.g.: /* getMaxTransactionCommitID */) DEF sql_text_substring = '&1.'; UNDEF 1; -- SELECT '&&cs_file_prefix._&&cs_script_name.' cs_file_name FROM DUAL; -- @@cs_internal/cs_signature.sql -- @@cs_internal/cs_spool_head.sql PRO SQL> @&&cs_script_name..sql "&&sql_text_substring." @@cs_internal/cs_spool_id.sql -- PRO SQL_TEXT_STR : "&&sql_text_substring." -- COL hot NEW_V hot FOR 9999; COL cold NEW_V cold FOR 9999; COL hash_value FOR 9999999999; COL sql_text FOR A80 TRUNC; -- PRO PRO BEFORE PRO ~~~~~~ WITH s AS ( SELECT /*+ MATERIALIZE NO_MERGE */ DISTINCT con_id, sql_id, hash_value, address, sql_text FROM v$sql WHERE &&cs_con_id. <> 1 -- executed on PDB and not on CDB$ROOT AND con_id = &&cs_con_id. AND '&&sql_text_substring.' IS NOT NULL AND sql_text LIKE '%&&sql_text_substring.%' AND sql_text NOT LIKE '%MATERIALIZE%' -- exclude SQL like this one! AND object_status = 'VALID' AND is_obsolete = 'N' AND is_shareable = 'Y' AND ROWNUM >= 1 /* MATERIALIZE */ ) SELECT c.full_hash_value, SUM(CASE WHEN c.property IS NOT NULL THEN 1 ELSE 0 END) AS hot, SUM(CASE WHEN c.property IS NULL THEN 1 ELSE 0 END) AS cold, s.sql_id, s.hash_value, s.address, s.sql_text FROM s, v$db_object_cache c WHERE c.con_id = s.con_id AND c.hash_value = s.hash_value AND c.addr = s.address AND c.name = s.sql_text AND c.namespace = 'SQL AREA' AND c.type = 'CURSOR' AND c.status = 'VALID' GROUP BY c.full_hash_value, s.sql_id, s.hash_value, s.address, s.sql_text ORDER BY c.full_hash_value, s.sql_id, s.hash_value, s.address, s.sql_text / -- PRO PRO SUMMARY PRO ~~~~~~~ WITH s AS ( SELECT /*+ MATERIALIZE NO_MERGE */ DISTINCT con_id, sql_id, hash_value, address, sql_text FROM v$sql WHERE &&cs_con_id. <> 1 -- executed on PDB and not on CDB$ROOT AND con_id = &&cs_con_id. AND '&&sql_text_substring.' IS NOT NULL AND sql_text LIKE '%&&sql_text_substring.%' AND sql_text NOT LIKE '%MATERIALIZE%' -- exclude SQL like this one! AND object_status = 'VALID' AND is_obsolete = 'N' AND is_shareable = 'Y' AND ROWNUM >= 1 /* MATERIALIZE */ ) SELECT SUM(CASE WHEN c.property IS NOT NULL THEN 1 ELSE 0 END) AS hot, SUM(CASE WHEN c.property IS NULL THEN 1 ELSE 0 END) AS cold FROM s, v$db_object_cache c WHERE c.con_id = s.con_id AND c.hash_value = s.hash_value AND c.addr = s.address AND c.name = s.sql_text AND c.namespace = 'SQL AREA' AND c.type = 'CURSOR' AND c.status = 'VALID' / -- PRO PAUSE Hit "return" to continue; or "control-c" then "return" to exit: -- PRO PRO MAKE HOT (IF COLD > 0 AND HOT = 0) PRO ~~~~~~~~ SET SERVEROUT ON; BEGIN IF TO_NUMBER(NVL(TRIM('&&cold.'), '0')) > 0 AND TO_NUMBER(NVL(TRIM('&&hot.'), '0')) = 0 THEN -- sql has not been marked as hot FOR i IN ( WITH s AS ( SELECT /*+ MATERIALIZE NO_MERGE */ DISTINCT con_id, sql_id, hash_value, address, sql_text FROM v$sql WHERE &&cs_con_id. <> 1 -- executed on PDB and not on CDB$ROOT AND con_id = &&cs_con_id. AND '&&sql_text_substring.' IS NOT NULL AND sql_text LIKE '%&&sql_text_substring.%' AND sql_text NOT LIKE '%MATERIALIZE%' -- exclude SQL like this one! AND object_status = 'VALID' AND is_obsolete = 'N' AND is_shareable = 'Y' AND ROWNUM >= 1 /* MATERIALIZE */ ) SELECT DISTINCT full_hash_value FROM s, v$db_object_cache c WHERE c.con_id = s.con_id AND c.hash_value = s.hash_value AND c.addr = s.address AND c.name = s.sql_text AND c.namespace = 'SQL AREA' AND c.type = 'CURSOR' AND c.status = 'VALID' AND c.property IS NULL -- COLD ) LOOP DBMS_OUTPUT.put_line('MARKHOT:'||i.full_hash_value); DBMS_SHARED_POOL.markhot(hash => i.full_hash_value, namespace => 0); END LOOP; END IF; END; / SET SERVEROUT OFF; -- PRO PRO SQL> @&&cs_script_name..sql "&&sql_text_substring." -- @@cs_internal/cs_spool_tail.sql @@cs_internal/cs_undef.sql @@cs_internal/cs_reset.sql --