Nov 21 2008

DBMS_XPLAN.PREPARE_PLAN_XML_QUERY

Tag: 11gR1, Query OptimizerChristian Antognini @ 1:11 pm

As of 11.1.0.7 in the package DBMS_XPLAN there is a new function:

FUNCTION prepare_plan_xml_query(plan_query IN VARCHAR2) RETURN VARCHAR2;

Simply put, the function takes as input a query that extract information from a plan table (e.g. PLAN_TABLE or V$SQL_PLAN) and builds a query based on SQLX functions that returns the output of the input query in XML.

Let’s have a look to an example:

  • At first we generate an execution plan with EXPLAIN PLAN.

SQL> EXPLAIN PLAN FOR
  2  SELECT *
  3  FROM scott.emp
  4  WHERE empno = 7788;

  • If we want to display all information stored in the plan table in a readable way, we can use a query like the following one.

SQL> SELECT *
  2  FROM table(dbms_xplan.display(format=>'advanced'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
Plan hash value: 4024650034

--------------------------------------------------------------------------------------
| Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |        |     1 |    37 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMP    |     1 |    37 |     1   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | EMP_PK |     1 |       |     0   (0)| 00:00:01 |
--------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1 / EMP@SEL$1
   2 - SEL$1 / EMP@SEL$1

Outline Data
-------------

  /*+
      BEGIN_OUTLINE_DATA
      INDEX_RS_ASC(@"SEL$1" "EMP"@"SEL$1" ("EMP"."EMPNO"))
      OUTLINE_LEAF(@"SEL$1")
      ALL_ROWS
      DB_VERSION('11.1.0.7')
      OPTIMIZER_FEATURES_ENABLE('11.1.0.7')
      IGNORE_OPTIM_EMBEDDED_HINTS
      END_OUTLINE_DATA
  */

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("EMPNO"=7788)

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "EMPNO"[NUMBER,22], "EMP"."ENAME"[VARCHAR2,10],
       "EMP"."JOB"[VARCHAR2,9], "EMP"."MGR"[NUMBER,22], "EMP"."HIREDATE"[DATE,7],
       "EMP"."SAL"[NUMBER,22], "EMP"."COMM"[NUMBER,22], "EMP"."DEPTNO"[NUMBER,22]
   2 - "EMP".ROWID[ROWID,10], "EMPNO"[NUMBER,22]

  • Such an output is useful for a human being. However, if we have to provide that information to an application for further processing, that output is not good. In such a situation the new function might be useful. In fact, we can let it generate a query based on SQLX functions that returns an XML fragment (as you will see later, the output it’s not a valid XML document).

SQL> SELECT dbms_xplan.prepare_plan_xml_query('SELECT * FROM plan_table') AS query
  2  FROM dual;

QUERY
----------------------------------------------------------------------------------
select xmlagg(xmlelement("operation",
                xmlattributes(operation as "name",
                              options  as "options",
                              id as "id",
                              depth as "depth",
                              position as "pos"),
                nvl2(object_name,
                     xmlelement("object",
                                 xmlcdata(object_name)), NULL),
                nvl2(cardinality, xmlelement("card", cardinality),
                     NULL),
                nvl2(bytes, xmlelement("bytes", bytes), NULL),
                nvl2(temp_space, xmlelement("temp_space",temp_space),
                     NULL),
                nvl2(cost, xmlelement("cost", cost), NULL),
                nvl2(io_cost, xmlelement("io_cost", io_cost), NULL),
                nvl2(cpu_cost, xmlelement("cpu_cost",cpu_cost),NULL),
                nvl2(time,
                     xmlelement("time",
                       xmlcdata(sys.dbms_xplan.format_time_s(time))),
                     NULL),
                nvl2(partition_start,
                     xmlelement("partition",
                       xmlattributes(partition_start as "start",
                                     partition_stop as "stop")),
                     NULL),
                nvl2(object_node, xmlelement("node", object_node),
                     NULL),
                nvl2(distribution,xmlelement("distrib",distribution),
                     NULL),
                nvl2(projection,
                  xmlelement("project", xmlcdata(projection)), NULL),
                nvl2(access_predicates,
                     xmlelement("predicates",
                                xmlattributes('access' as "type"),
                                xmlcdata(access_predicates)),
                     NULL),
                nvl2(filter_predicates,
                     xmlelement("predicates",
                                 xmlattributes('filter' as "type"),
                                 xmlcdata(filter_predicates)),
                     NULL),
                nvl2(qblock_name,
                     xmlelement("qblock", xmlcdata(qblock_name)),
                     NULL),
               (case when other_xml is null then null
                      else xmltype(other_xml) end)
             )
           ) plan
from (SELECT * FROM plan_table)

  • By running that query we get the following XML fragment (I formatted the output to make it readable). As you can see, it contains all information previously provided by the function DISPLAY.

<operation name="SELECT STATEMENT" id="0" depth="0" pos="1">
  <card>1</card>
  <bytes>37</bytes>
  <cost>1</cost>
  <io_cost>1</io_cost>
  <cpu_cost>8461</cpu_cost>
  <time><![CDATA[00:00:01 ]]></time>
</operation>
<operation name="TABLE ACCESS" options="BY INDEX ROWID" id="1" depth="1" pos="1">
  <object><![CDATA[EMP]]></object>
  <card>1</card>
  <bytes>37</bytes>
  <cost>1</cost>
  <io_cost>1</io_cost>
  <cpu_cost>8461</cpu_cost>
  <time><![CDATA[00:00:01 ]]></time>
  <project><![CDATA["EMPNO"[NUMBER,22], 
                    "EMP"."ENAME"[VARCHAR2,10], 
                    "EMP"."JOB"[VARCHAR2,9], 
                    "EMP"."MGR"[NUMBER,22], 
                    "EMP"."HIREDATE"[DATE,7], 
                    "EMP"."SAL"[NUMBER,22], 
                    "EMP"."COMM"[NUMBER,22], 
                    "EMP"."DEPTNO"[NUMBER,22]]]></project>
  <qblock><![CDATA[SEL$1]]></qblock>
  <other_xml>
    <info type="db_version">11.1.0.7</info>
    <info type="parse_schema"><![CDATA["OPS$CHA"]]></info>
    <info type="plan_hash">4024650034</info>
    <info type="plan_hash_2">1148924698</info>
    <outline_data>
      <hint><![CDATA[INDEX_RS_ASC(@"SEL$1" "EMP"@"SEL$1" ("EMP"."EMPNO"))]]></hint>
      <hint><![CDATA[OUTLINE_LEAF(@"SEL$1")]]></hint>
      <hint><![CDATA[ALL_ROWS]]></hint>
      <hint><![CDATA[DB_VERSION('11.1.0.7')]]></hint>
      <hint><![CDATA[OPTIMIZER_FEATURES_ENABLE('11.1.0.7')]]></hint>
      <hint><![CDATA[IGNORE_OPTIM_EMBEDDED_HINTS]]></hint>
    </outline_data>
  </other_xml>
</operation>
<operation name="INDEX" options="UNIQUE SCAN" id="2" depth="2" pos="1">
  <object><![CDATA[EMP_PK]]></object>
  <card>1</card>
  <cost>0</cost>
  <io_cost>0</io_cost>
  <cpu_cost>1050</cpu_cost>
  <time><![CDATA[00:00:01 ]]></time>
  <project><![CDATA["EMP".ROWID[ROWID,10], 
                    "EMPNO"[NUMBER,22]]]></project>
  <predicates type="access"><![CDATA["EMPNO"=7788]]></predicates>
  <qblock><![CDATA[SEL$1]]></qblock>
</operation>


Nov 17 2008

TVD$XTAT 4.0 Beta 8

Tag: SQL Trace, TOP, TVD$XTATChristian Antognini @ 10:08 pm

This is just a short note to point out that I just uploaded under the section Downloadable Files of TOP a new version of TVD$XTAT.

The change log since Beta 7 is the following:

  • Improved generation of synthetic cursors (particularly for RPC and XCTEND)
  • Added support for 11.1.0.7 formatting of XCTEND
  • Added check for questionable values for cpu and elapsed time
  • Extended the list of recognized data types
  • Fix to avoid Java 1.6.0 bug 6506304
  • Fix to correctly handle attribution of bind variables
  • Fix to correctly handle bind variables containing invalid numbers
  • Fix to correctly handle bind variables containing the value NULL
  • Fix to avoid parse errors for bind variables containing kkscoacd lines
  • Fix to avoid warnings about freed cursors
  • Fix to avoid warnings for lines beginning with “*** TRACE CONTINUED FROM FILE”

Please, do not hesitate to contact me if you have any kind of problem while using it.


Nov 13 2008

Hotsos Symposium 2009

Tag: SpeakingChristian Antognini @ 7:00 am

Every March since 2004 I use to spend several days in Dallas. The reason is quite simple… people from around the world sharing my own interests gather there to attend Hotsos Symposium. If, like me, you are focusing on getting the most out of Oracle, this is one of the conferences that you should not miss.

Few days ago Hotsos announced the list of speakers for Symposium 2009. Once again, I’m really glad to present there (I’ll speak about bloom filters).

The keynote speaker will be Chris Date. I’m looking forward to hear what he has to say about the foundation of the database field, i.e. about the relation model.

Hope to see you all there next March!


Nov 11 2008

Invisible Indexes and Hints

Tag: 11gR1, Bug, Indexes, Query OptimizerChristian Antognini @ 6:02 pm

In this post I would like to remove some misinformation about the utilization of hints with invisible indexes.

Let’s start by providing you what two sources say about that topic:

Both sources point out that a hint can be used to compel the query optimizer to use an invisible index. Both also provide an example (not shown here). But, what is more important, both are wrong! In other words, a hint cannot be used to compel the query optimizer to use an invisible index.

What’s going on?!?

The problem is that this specific information used to be correct for the beta release of Oracle Database 11g. But that behavior was a bug, not a feature! Therefore, once the bug was fixed, this piece of information was no longer valid.

This is what happens when authors use beta releases for doing their tests…