Search notes:

Oracle PLAN_TABLE: Column OTHER_XML

The column other_xml of the plan_table displays additional, differently structured (hence the XML format) for an execution step. Such information includes:
create table tq84_tab (nm number, tx varchar2(10));

explain plan
   set statement_id = 'get_other_xml'
for
  select /*+ invalid_hint(t) */
     nm,
     tx
  from
     tq84_tab t;

select
   other_xml
from
   plan_table
where
   statement_id = 'get_other_xml' and
   other_xml is not null;
The (manually formatted) value of other_xml for this statement is:
<other_xml>

  <info type="has_user_tab"             >yes</info>
  <info type="db_version"               >19.0.0.0</info>
  <info type="parse_schema"             ><![CDATA["RENE"]]></info>
  <info type="dynamic_sampling" note="y">2</info>
  <info type="plan_hash_full"           >1066212411</info>
  <info type="plan_hash"                >1254052927</info>
  <info type="plan_hash_2"              >1066212411</info>

  <stats type="compilation">
    <stat name="bg">8</stat>
  </stats>

  <qb_registry>
    <q o="2" f="y">
      <n><![CDATA[SEL]]></n>
      <f>
        <h>
          <t><![CDATA[T]]></t><s><![CDATA[SEL]]></s>
        </h>
      </f>
    </q>
  </qb_registry>

  <outline_data>
    <hint><![CDATA[FULL(@"SEL" "T"@"SEL")             ]]></hint>
    <hint><![CDATA[OUTLINE_LEAF(@"SEL")               ]]></hint>
    <hint><![CDATA[ALL_ROWS                           ]]></hint>
    <hint><![CDATA[DB_VERSION('19.1.0')               ]]></hint>
    <hint><![CDATA[OPTIMIZER_FEATURES_ENABLE('19.1.0')]]></hint>
    <hint><![CDATA[IGNORE_OPTIM_EMBEDDED_HINTS        ]]></hint>

  </outline_data>

  <hint_usage>
    <q>
      <n><![CDATA[SEL]]></n>
      <h o="EM" st="PE">
        <x><![CDATA[invalid_hint]]></x>
      </h>
    </q>
  </hint_usage>

</other_xml>

Exactly one record with OTHER_XML for a plan

As far as I can tell, there is exactly one record with other_xml is not null for a plan:
select
   count(case when other_xml is not null then 'x' end) cnt_xml,
   count(*) cnt,
   sql_id,
   plan_hash_value
from
   dba_hist_sql_plan
where
   dbid = (select dbid from v$database)
group by
   sql_id,
   plan_hash_value
order by
   count(case when other_xml is not null then 'x' end) desc nulls first;

Second level XML elements

The following query is an attempt to find the second level (one below the root element other_xml, that is) XML elements:
select
   count(*),
   t.name
from
-- v$sql_plan        p,
   dba_hist_sql_plan p,
   xmlTable(
        '/other_xml/*'
         passing xmlType(p.other_xml)
      columns
         name varchar2(4000) path './name()'
   ) t
where
   p.other_xml is not null
group by
   t.name
order by
   t.name;
On a 19c database, this query returned these elements:

info

Attributes of info

The following query finds the possible attribute names of the <info> element. In 19c, these are
  • id
  • note
  • type
select
   count(*),
   t.name
from
-- v$sql_plan p,
   dba_hist_sql_plan p,
   xmlTable(
        '/other_xml/info/@*'
         passing xmlType(p.other_xml)
      columns
         name varchar2(4000) path './name()'
   ) t
where
   p.other_xml is not null
group by
   t.name
order by
   t.name;

Values of the type attribute

The values of the type attribute incude
  • adaptive_plan
  • baseline_repro_fail
  • cardinality_feedback
  • cpu_rate
  • db_version
  • derived_cpu_dop
  • derived_io_dop
  • dop
  • dop_op_reason
  • dop_reason
  • dynamic_sampling
  • has_user_tab
  • idl_reason
  • index_size
  • io_rate
  • nodeid/pflags
  • parse_schema
  • pdml_reason
  • performance_feedback
  • plan_hash
  • plan_hash_2
  • plan_hash_full
  • px_ext_opns
  • px_in_memory
  • px_in_memory_imc
  • queuing_reason
  • slave_parse
  • sql_patch
These values can be queried like so:
select
   count(*),
   t.name
from
-- v$sql_plan p,
   dba_hist_sql_plan p,
   xmlTable(
        '/other_xml/info/@type'
         passing xmlType(p.other_xml)
      columns
         name varchar2(4000) path '.'
   ) t
where
   p.other_xml is not null
group by
   t.name
order by
   t.name;

hint_usage

--
-- As so often, Frank Pachot's insights were very helpful
-- https://franckpachot.medium.com/oracle-19c-hint-usage-reporting-345563a461f0
--
with h as (
select
-- plan.sql_id,
-- other_xml,
   plan.qblock_name                                          query_block_name_plan,
   qb.name                                                   query_block_name,
   qb.status                                                 query_block_status  ,
-- qb.hints.getClobVal()                                     hints,
-- hint.o,                                                   -- ???
   case  hint.status
         when 'PE'   then 'Parse error'
         when 'UR'   then 'Unresolved'
         when 'NU'   then 'Not used (NU)'
         when 'PU'   then 'Not used (PU)'
         else              hint.status
   end                                                       hint_status   ,
   --
   lower(regexp_replace(hint, '([^(]*).*'   , '\1'))         hint_name     ,
   lower(regexp_substr(hint, '\((*.*)\)'    ))               hint_arguments,  
   hint.hint                                                               , -- Text of hint
   hint.reason,   -- index specified in the hint doesn't exist,
                  -- rejected by IGNORE_OPTIM_EMBEDDED_HINTS
                  -- same QB_NAME hints for different query blocks
                  -- ORDER_SUBQ referenced query block name, which cannot be found
                  -- hint overridden by another in parent query block
   hint.obj_alias,
   hint.hint_ts
from
-- plan_table        plan,
-- v$sql_plan        plan,
   dba_hist_sql_plan plan,
   xmlTable('/*/hint_usage/q' passing xmltype(other_xml)
                 columns
                    name     VARCHAR2(4000) path './n',
                    status   varchar2(   3) path '@st',  -- @st = status ?
                    hints    xmlType        path './*'
   ) qb,
--
-- Search for hints with '//h' because
-- the <h> tag sometimes occurs directly below <hint_usage> and
-- sometimes below <t>.
--
   xmlTable('//h'   passing qb.hints
                    columns
                       o              varchar2(   3) path '@o'    ,       -- EM or OU or ?
                       status         varchar2(   3) path '@st'   ,
                       hint           varchar2(4000) path 'x'     ,       -- The text of the hint (clob?)
                       reason         varchar2(4000) path 'r'     ,      
                       obj_alias      varchar2(4000) path './../f',
                       hint_ts        varchar2(   3) path './../@st'
   ) hint  
where
   other_xml is not null
)
select
   *

-- hint_status,
-- hint_name,
-- hint_arguments
-- hint,
-- obj_alias,
-- hint_ts

   -- count(*), hint_name, hint_status
from
   h
;  

Querying OTHER_XML with XPATH expressions

other_xml can be queried with XPath expressions.
create or replace view tq84_plan_other_xml as
select /*+ parallel(32) */
   p.dbid,
   p.operation,
   p.options,
   p.position,
   t.parse_schema,
-- t.cpu_rate,
   t.idl_reason,
   t.px_in_memory, t.px_in_memory_imc,
   t.queuing_reason,
-- t.stats_type,
   t.stat_comp_bg,
-- t.nodeid_pflags,
   t.index_size,
   t.dop, t.dop_reason, t.pdml_reason,
   t.dynamic_sampling,
   t.adaptive_plan,
   t.baseline,
   t.baseline_repro_fail          ,
   t.outline,
   t.sql_patch,
   t.sql_profile,
   t.plan_hash_full,
   t.plan_hash, p.plan_hash_value,    -- Equal
   t.plan_hash_2,
 
   t.cardinality_feedback         ,
   t.performance_feedback         ,
   t.rely_constraint              ,
   t.xml_suboptimal               ,
   t.gtt_session_st               ,
   t.gather_stats_on_cnvtl_dml    ,
   t.opt_use_stats_on_cnvtl_dml   ,
   t.slave_parse                  ,
   t.cross_shard_query            ,
   t.shard_id                     ,
   t.result_checksum              ,
   t.row_shipping,
   x.sql_text,
   p.other_xml
from
   dba_hist_sql_plan p  join
   dba_hist_sqltext  x on p.sql_id = x.sql_id,
   xmlTable(
       '/other_xml'
         passing xmlType(p.other_xml)
      columns
         parse_schema                  varchar2( 128) path './info[@type="parse_schema"                            ]',
--       cpu_rate                      varchar2(4000) path './info[@type="cpu_rate"                                ]',
         dop                           integer        path './info[@type="dop"                                     ]',
         dop_reason                    varchar2(  31) path './info[@type="dop_reason"                              ]',      -- hint, parallel threshold, degree limit, table property, no expensive parallel operation, session
         px_in_memory                  varchar2(   3) path './info[@type="px_in_memory"                            ]',      -- yes, no, null
         px_in_memory_imc              varchar2(   3) path './info[@type="px_in_memory_imc"                        ]',      -- no, null (also yes?)
         pdml_reason                   varchar2(  54) path './info[@type="pdml_reason"                             ]',      -- insert values was used, returning clause is present, function is not pure and not declared parallel enabled, PDML is disabled in current session, object is not decorated with parallel clause, single fragment or non partitioned table used, ...
         idl_reason                    varchar2(  50) path './info[@type="idl_reason"                              ]',      -- remote table used, insert values with no append values hint used, no append hint given and not executing in parallel
         index_size                    integer        path './info[@type="index_size"                              ]',      -- Filled for CREATE INDEX statements.
        
         plan_hash_full                integer        path './info[@type="plan_hash_full"                          ]',
         plan_hash                     integer        path './info[@type="plan_hash"                               ]',
         plan_hash_2                   integer        path './info[@type="plan_hash_2"                             ]',
        
         dynamic_sampling              varchar2(4000) path './info[@type="outline"                                 ]',       --
         adaptive_plan                 varchar2(   3) path './info[@type="adaptive_plan"                           ]',       -- yes or null ?
         sql_profile                   varchar2( 128) path './info[@type="sql_profile"                             ]',       -- "SYS_SQLPROF_015ff2bc9c520000"
         baseline                      varchar2(4000) path './info[@type="baseline"                                ]',       --
         baseline_repro_fail           varchar2(   3) path './info[@type="baseline_repro_fail"                     ]',       -- yes, null
         outline                       varchar2(4000) path './info[@type="outline"                                 ]',       --        
         slave_parse                   varchar2(   8) path './info[@type="slave_parse"                             ]',       -- regular, outlined
         sql_patch                     varchar2(4000) path './info[@type="sql_patch"                               ]',       --
         queuing_reason                varchar2(4000) path './info[@type="queuing_reason"                          ]',       --
 
         stat_comp_bg                  integer        path './stats[@type="compilation"]/stat[@name="bg"]           ',       --
 
--       nodeid_pflags                 varchar2( 100) path './info[@type="nodeid/pflags"                           ]',       --
--       stats_type                    varchar2(4000) path './stats/@type"                                         ]',
         cardinality_feedback          varchar2(   3) path './info[@type="cardinality_feedback"                    ]',       -- yes, null
         performance_feedback          varchar2(   3) path './info[@type="performance_feedback"                    ]',       -- yes, null
         rely_constraint               varchar2(4000) path './info[@type="rely_constraint"                         ]',
         xml_suboptimal                varchar2(4000) path './info[@type="xml_suboptimal"                          ]',
         gtt_session_st                varchar2(4000) path './info[@type="gtt_session_st"                          ]',
         gather_stats_on_cnvtl_dml     varchar2(4000) path './info[@type="gather_stats_on_conventional_dml"        ]',
         opt_use_stats_on_cnvtl_dml    varchar2(4000) path './info[@type="optimizer_use_stats_on_conventional_dml" ]',
         cross_shard_query             varchar2(4000) path './info[@type="cross_shard_query"                       ]',
         shard_id                      varchar2(4000) path './info[@type="shard_id"                                ]',
         result_checksum               varchar2(4000) path './info[@type="result_checksum"                         ]',
         row_shipping                  varchar2(4000) path './info[@type="row_shipping"                            ]'
   ) t
where
   p.other_xml is not null
;

Index

Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 8 attempt to write a readonly database in /home/httpd/vhosts/renenyffenegger.ch/php/web-request-database.php:78 Stack trace: #0 /home/httpd/vhosts/renenyffenegger.ch/php/web-request-database.php(78): PDOStatement->execute(Array) #1 /home/httpd/vhosts/renenyffenegger.ch/php/web-request-database.php(30): insert_webrequest_('/notes/developm...', 1737532356, '3.135.198.82', 'Mozilla/5.0 App...', NULL) #2 /home/httpd/vhosts/renenyffenegger.ch/httpsdocs/notes/development/databases/Oracle/SQL/statement/verbs/explain/plan_table/columns/other_xml/index(417): insert_webrequest() #3 {main} thrown in /home/httpd/vhosts/renenyffenegger.ch/php/web-request-database.php on line 78