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>

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.
with x as (
   select xmlType(other_xml) other_xml from v$sql_plan where other_xml is not null
)
select 
   extractvalue(other_xml, '/*/info[@type = "plan_hash"]'                              ) plan_hash,
   extractvalue(other_xml, '/*/info[@type = "adaptive_plan"]'                          ) adaptive_plan,
   extractvalue(other_xml, '/*/info[@type = "sql_profile"]'                            ) sql_profile,
   extractvalue(other_xml, '/*/info[@type = "sql_patch"]'                              ) sql_patch,
   extractvalue(other_xml, '/*/info[@type = "baseline"]'                               ) baseline,
   extractvalue(other_xml, '/*/info[@type = "outline"]'                                ) outline,
   extractvalue(other_xml, '/*/info[@type = "dynamic_sampling"]'                       ) dynamic_sampling,
   extractvalue(other_xml, '/*/info[@type = "dop"]'                                    ) dop,
   extractvalue(other_xml, '/*/info[@type = "dop_reason"]'                             ) dop_reason,
   extractvalue(other_xml, '/*/info[@type = "pdml_reason"]'                            ) pdml_reason,
   extractvalue(other_xml, '/*/info[@type = "idl_reason"]'                             ) idl_reason,
   extractvalue(other_xml, '/*/info[@type = "queuing_reason"]'                         ) queuing_reason,
   extractvalue(other_xml, '/*/info[@type = "px_in_memory"]'                           ) px_in_memory,
   extractvalue(other_xml, '/*/info[@type = "px_in_memory_imc"]'                       ) px_in_memory_imc,
   extractvalue(other_xml, '/*/info[@type = "row_shipping"]'                           ) row_shipping,
   extractvalue(other_xml, '/*/info[@type = "index_size"]'                             ) index_size,
   extractvalue(other_xml, '/*/info[@type = "result_checksum"]'                        ) result_checksum,
   extractvalue(other_xml, '/*/info[@type = "cardinality_feedback"]'                   ) cardinality_feedback,
   extractvalue(other_xml, '/*/info[@type = "performance_feedback"]'                   ) performance_feedback,
   extractvalue(other_xml, '/*/info[@type = "rely_constraint"]'                        ) rely_constraint,
   extractvalue(other_xml, '/*/info[@type = "xml_suboptimal"]'                         ) xml_suboptimal,
   extractvalue(other_xml, '/*/spd/cu'                                                 ) spd_cu,
   extractvalue(other_xml, '/*/info[@type = "gtt_session_st"]'                         ) gtt_session_st,
   extractvalue(other_xml, '/*/info[@type = "gather_stats_on_conventional_dml"]'       ) gather_stats_on_cnvtl_dml,
   extractvalue(other_xml, '/*/info[@type = "optimizer_use_stats_on_conventional_dml"]') opt_use_stats_on_cnvtl_dml,
   extractvalue(other_xml, '/*/info[@type = "slave_parse"]'                            ) slave_parse,
   extractvalue(other_xml, '/*/info[@type = "baseline_repro_fail"]'                    ) baseline_repro_fail,
   extractvalue(other_xml, '/*/info[@type = "cross_shard_query"]'                      ) cross_shard_query,
   extractvalue(other_xml, '/*/info[@type = "shard_id"]'                               ) shard_id,
   extract     (other_xml, '/*/hint_usage').getClobVal()
 from
   x
;

Index