Oracle Explain Plan – 2

September 25, 2009

Zurück

  Interpreting Explain Plan 

What’s an explain plan?

An explain plan is a representation of the access path that is taken when a query is executed within Oracle.

Query processing can be divided into 7 phases:

[1] Syntactic Checks the syntax of the query
[2] Semantic Checks that all objects exist and are accessible
[3] View Merging Rewrites query as join on base tables as opposed to using views
[4] Statement
     Transformation
Rewrites query transforming some complex constructs into simpler ones where appropriate (e.g. subquery merging, in/or transformation)
[5] Optimization Determines the optimal access path for the query to take. With the Rule Based Optimizer (RBO) it uses a set of heuristics to determine access path. With the Cost Based Optimizer (CBO) we use statistics to analyze the relative costs of accessing objects.
[6] QEP Generation QEP = Query Evaluation Plan
[7] QEP Execution QEP = Query Evaluation Plan

Steps [1]-[6] are handled by the parser. Step [7] is the execution of the statement.

The explain plan is produced by the parser. Once the access path has been decided upon it is stored in the library cache together with the statement itself. We store queries in the library cache based upon a hashed representation  of that query. When looking for a statement in the library cache, we first apply a hashing algorithm to the statement and then we look for this hash value in the library cache. This access path will be used until the query is reparsed.

Terminology

Row Source A set of rows used in a query may be a select from a base object or the result set returned by joining 2 earlier row sources
Predicate where clause of a query
Tuples rows
Driving Table This is the row source that we use to seed the query. If this returns a lot of rows then this can have a negative affect on all subsequent operations
Probed Table This is the object we lookup data in after we have retrieved relevant key data from the driving table.

How does Oracle access data?

At the physical level Oracle reads blocks of data. The smallest amount of data read is a single Oracle block, the largest is constrained by operating system limits (and multiblock i/o). Logically Oracle finds the data to read by using the following methods:

  • Full Table Scan (FTS)
  • Index Lookup (unique & non-unique)
  • Rowid

Explain plan Hierarchy

Simple explain plan:

Query Plan
—————————————–
SELECT STATEMENT     [CHOOSE] Cost=1234
  TABLE ACCESS FULL LARGE [:Q65001] [ANALYZED]

The rightmost uppermost operation of an explain plan is the first thing that the explain plan will execute. In this case TABLE ACCESS FULL LARGE is the first operation. This statement means we are doing a full table scan of table LARGE. When this operation completes then the resultant row source is passed up to the
next level of the query for processing. In this case it is the SELECT STATEMENT which is the top of the query.

[CHOOSE] is an indication of the optimizer_goal for the query. This DOES NOT necessarily indicate that plan has actually used this goal. The only way to confirm this is to check the
cost= part of the explain plan as well. For example the following query indicates that the CBO has been used because there is a cost in the cost field:

SELECT STATEMENT     [CHOOSE] Cost=1234

However the explain plan below indicates the use of the RBO because the cost field is blank:

SELECT STATEMENT     [CHOOSE] Cost=

The cost field is a comparative cost that is used internally to determine the best cost for particular plans. The costs of different statements are not really directly comparable.

[:Q65001] indicates that this particular part of the query is being executed in parallel. This number indicates that the operation will be processed by a parallel query slave as opposed to being executed serially.

[ANALYZED] indicates that the object in question has been analyzed and there are currently statistics available for the CBO to use. There is no indication of the ‘level’ of analysis done.

Access Methods in detail

Full Table Scan (FTS)

In a FTS operation, the whole table is read up to the high water mark (HWM). The HWM marks the last block in the table that has ever had data written to it. If you have deleted all the rows then you will still read up to the HWM. Truncate resets the HWM back to the start of the table. FTS uses multiblock i/o to read the blocks from disk. Multiblock i/o is controlled by the parameter <PARAM:db_block_multi_block_read_count>.

This defaults to:

db_block_buffers / ( (PROCESSES+3) / 4 )

Maximum values are OS dependant

Buffers from FTS operations are placed on the Least Recently Used (LRU) end of the buffer cache so will be quickly aged out. FTS is not recommended for large tables unless you are reading >5-10% of it (or so) or you intend to run in parallel.

Example FTS explain plan:

SQL> explain plan for select * from dual;

Query Plan
—————————————–
SELECT STATEMENT     [CHOOSE] Cost=
  TABLE ACCESS FULL DUAL

Index lookup

Data is accessed by looking up key values in an index and returning rowids. A rowid uniquely identifies an individual row in a particular data block. This block is read via single block i/o.

In this example an index is used to find the relevant row(s) and then the table is accessed to lookup the ename column (which is not included in the index):

SQL> explain plan for
select empno,ename from emp where empno=10;
Query Plan

————————————
SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
    INDEX UNIQUE SCAN EMP_I1

Notice the ‘TABLE ACCESS BY ROWID’ section. This indicates that the table data is not being accessed via a FTS operation but rather by a rowid lookup. In this case the rowid has been produced by looking up values in the index first. The index is being accessed by an ‘INDEX UNIQUE SCAN’ operation. This is explained below. The index name in this case is EMP_I1. If all the required data resides in the index then a table lookup may be unnecessary and all you will see is an index access with no table access.

In the following example all the columns (empno) are in the index. Notice that no table access takes place:

SQL> explain plan for
select empno from emp where empno=10;

Query Plan
————————————
SELECT STATEMENT [CHOOSE] Cost=1
  INDEX UNIQUE SCAN EMP_I1

Indexes are presorted so sorting may be unecessary if the sort order required is the same as the index.

SQL> explain plan for select empno,ename from emp
where empno > 7876 order by empno;

Query Plan
————————————————————-
SELECT STATEMENT   [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
  INDEX RANGE SCAN EMP_I1 [ANALYZED]

In this case the index is sorted so ther rows will be returned in the order of the index hence a sort is unecessary.

SQL> explain plan for
select /*+ Full(emp) */ empno,ename from emp
where empno> 7876 order by empno;

Query Plan
————————————————————-
SELECT STATEMENT   [CHOOSE] Cost=9
  SORT ORDER BY
    TABLE ACCESS FULL EMP [ANALYZED]  Cost=1 Card=2 Bytes=66

Because we have forced a FTS the data is unsorted and so we must sort the data
after it has been retrieved.

There are 4 methods of index lookup:

  • index unique scan
  • index range scan
  • index full scan
  • index fast full scan

Index unique scan

Method for looking up a single key value via a unique index. Always returns a single value You must supply AT LEAST the leading column of the index to access data via the index, However this may return > 1 row as the uniqueness will not be guaranteed.

SQL> explain plan for
select empno,ename from emp where empno=10;

Query Plan
————————————
SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
    INDEX UNIQUE SCAN EMP_I1

Index range scan

Method for accessing multiple column values You must supply AT LEAST the leading column of the index to access data via the index Can be used for range operations (e.g. > < <> >= <= between)

SQL> explain plan for select empno,ename from emp
where empno > 7876 order by empno;

Query Plan
——————————————————-
SELECT STATEMENT   [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
  INDEX RANGE SCAN EMP_I1 [ANALYZED]

A non-unique index may return multiple values for the predicate col1 = 5 and will use an index range scan

SQL> explain plan for select mgr from emp where mgr = 5

Query plan
——————–
SELECT STATEMENT [CHOOSE] Cost=1
  INDEX RANGE SCAN EMP_I2 [ANALYZED]

Index Full Scan

In certain circumstances it is possible for the whole index to be scanned as opposed to a range scan (i.e. where no constraining predicates are provided for a table). Full index scans are  only available in the CBO as otherwise we are unable to determine whether a full scan would be a good idea or not. We choose an index Full Scan when we have statistics that indicate that it is going to be more efficient than a Full table scan and a sort.

For example we may do a Full index scan when we do an unbounded scan of an index and want the data to be ordered in the index order. The optimizer may decide that selecting all the information from the index and not sorting is more efficient than doing a FTS or a Fast Full Index Scan and then sorting.

An Index full scan will perform single block i/o’s and so it may prove to be inefficient. Index BE_IX is a concatenated index on big_emp (empno,ename)

SQL> explain plan for select empno,ename
     from big_emp order by empno,ename;

Query Plan
————————————————————
SELECT STATEMENT   [CHOOSE] Cost=26
  INDEX FULL SCAN BE_IX [ANALYZED]

Index Fast Full Scan

Scans all the block in the index Rows are not returned in sorted order Introduced in 7.3 and requires V733_PLANS_ENABLED=TRUE and CBO may be hinted using INDEX_FFS hint uses multiblock i/o can be executed in parallel can be used to access second column of concatenated indexes. This is because we are selecting all of the index.

Note that INDEX FAST FULL SCAN is the mechinism behind fast index create and recreate. Index BE_IX is a concatenated index on big_emp (empno,ename)

SQL> explain plan for select empno,ename from big_emp;

Query Plan
——————————————
SELECT STATEMENT   [CHOOSE] Cost=1
  INDEX FAST FULL SCAN BE_IX [ANALYZED]

Selecting the 2nd column of concatenated index:

SQL> explain plan for select ename from big_emp;

Query Plan
——————————————
SELECT STATEMENT   [CHOOSE] Cost=1
  INDEX FAST FULL SCAN BE_IX [ANALYZED]

Rowid

This is the quickest access method available Oracle simply retrieves the block specified and extracts the rows it is interested in. Most frequently seen in explain plans as Table access by Rowid

SQL> explain plan for select * from dept where rowid = ‘:x’;

Query Plan
————————————
SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID DEPT [ANALYZED]

Table is accessed by rowid following index lookup:

SQL> explain plan for
select empno,ename from emp where empno=10;

Query Plan
————————————
SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
    INDEX UNIQUE SCAN EMP_I1

Joins

A Join is a predicate that attempts to combine 2 row sources We only ever join 2 row sources together Join steps are always performed serially even though underlying row sources may have been accessed in parallel. Join order – order in which joins are performed

The join order makes a significant difference to the way in which the query is executed. By accessing particular row sources first, certain predicates may be satisfied that are not satisfied by with other join orders. This may prevent certain access paths from being taken.

Suppose there is a concatenated index on A(a.col1,a.col2). Note that a.col1 is the leading column. Consider the following query:

select A.col4
from   A,B,C
where  B.col3 = 10
and    A.col1 = B.col1
and    A.col2 = C.col2
and    C.col3 = 5

We could represent the joins present in the query using the following schematic:

  B     <—> A <—>    C
col3=10                col3=5

There are really only 2 ways we can drive the query: via B.col3 or C.col3. We would have to do a Full scan of A to be able to drive off it. This is unlikely to be efficient with large tables;

If we drive off table B, using predicate B.col3=10 (as a filter or lookup key) then we will retrieve the value for B.col1 and join to A.col1. Because we have now filled the leading column of the concatenated index on table A we can use this index to give us values for A.col2 and join to A.

However if we drive of table c, then we only get a value for a.col2 and since this is a trailing column of a concatenated index and the leading column has not been supplied at this point, we cannot use the index on a to lookup the data.

So it is likely that the best join order will be B A C. The CBO will obviously use costs to establish whether the individual access paths are a good idea or not.

If the CBO does not choose this join order then we can hint it by changing the from
clause to read:

from B,A,C

and using the /*+ ordered */ hint. The resultant query would be:

select /*+ ordered */ A.col4
from   B,A,C
where  B.col3 = 10
and    A.col1 = B.col1
and    A.col2 = C.col2
and    C.col3 = 5

Join Types

  • Sort Merge Join (SMJ)
  • Nested Loops (NL)
  • Hash Join

Sort Merge Join

Rows are produced by Row Source 1 and are then sorted Rows from Row Source 2 are then produced and sorted by the same sort key as Row Source 1. Row Source 1 and 2 are NOT accessed concurrently Sorted rows from both sides are then merged together (joined)

                   MERGE
                 /      \
            SORT        SORT
             |             |
        Row Source 1  Row Source 2

If the row sources are already (known to be) sorted then the sort operation is unecessary as long as both ’sides’ are sorted using the same key. Presorted row sources include indexed columns and row sources that have already been sorted in earlier steps. Although the merge of the 2 row sources is handled serially, the row sources could be accessed in parallel.

SQL> explain plan for
select /*+ ordered */ e.deptno,d.deptno
from emp e,dept d
where e.deptno = d.deptno
order by e.deptno,d.deptno;

Query Plan
————————————-
SELECT STATEMENT [CHOOSE] Cost=17
  MERGE JOIN
    SORT JOIN
      TABLE ACCESS FULL EMP [ANALYZED]
    SORT JOIN
      TABLE ACCESS FULL DEPT [ANALYZED]

Sorting is an expensive operation, especially with large tables. Because of this, SMJ is often not a particularly efficient join method.

Nested Loops

First we return all the rows from row source 1 Then we probe row source 2 once for each row returned from row source 1

Row source 1
~~~~~~~~~~~~
Row 1 ————–       — Probe ->       Row source 2
Row 2 ————–       — Probe ->       Row source 2
Row 3 ————–       — Probe ->       Row source 2

Row source 1 is known as the outer table
Row source 2 is known as the inner table

Accessing row source 2 is known a probing the inner table For nested loops to be efficient it is important that the first row source returns as few rows as possible as this directly controls the number of probes of the second row source. Also it helps if the access method for row source 2 is efficient as this operation is being repeated once for every row returned by row source 1.

SQL> explain plan for
select a.dname,b.sql
from dept a,emp b
where a.deptno = b.deptno;

Query Plan
————————-
SELECT STATEMENT [CHOOSE] Cost=5
  NESTED LOOPS
    TABLE ACCESS FULL DEPT [ANALYZED]
    TABLE ACCESS FULL EMP [ANALYZED]

Hash Join

New join type introduced in 7.3 More efficient in theory than NL & SMJ Only accessible via the CBO Smallest row source is chosen and used to build a hash table and a bitmap The second row source is hashed and checked against the hash table looking for joins. The bitmap is used as a quick lookup to check if rows are in the hash table and are especially useful when the hash table is too large to fit in memory.

SQL> explain plan for
select /*+ use_hash(emp) */ empno
from emp,dept
where emp.deptno = dept.deptno;

Query Plan
—————————-
SELECT STATEMENT  [CHOOSE] Cost=3
  HASH JOIN
    TABLE ACCESS FULL DEPT
    TABLE ACCESS FULL EMP

Hash joins are enabled by the parameter HASH_JOIN_ENABLED=TRUE in the init.ora or session. TRUE is the default in 7.3

Cartesian Product

A Cartesian Product is done where they are no join conditions between 2 row sources and there is no alternative method of accessing the data Not really a join as such as there is no join! Typically this is caused by a coding mistake where a join has been left out. It can be useful in some circumstances – Star joins uses cartesian products.

Notice that there is no join between the 2 tables:

SQL> explain plan for
select emp.deptno,dept,deptno
from emp,dept

Query Plan
——————————
SLECT STATEMENT [CHOOSE] Cost=5
  MERGE JOIN CARTESIAN
    TABLE ACCESS FULL DEPT
    SORT JOIN
      TABLE ACCESS FULL EMP

The CARTESIAN keyword indicate that we are doing a cartesian product.

Operations

Operations that show up in explain plans

  • sort
  • filter
  • view

Sorts

There are a number of different operations that promote sorts

  • order by clauses
  • group by
  • sort merge join

Note that if the row source is already appropriately sorted then no sorting is required. This is now indicated in 7.3:

SORT GROUP BY NOSORT
     INDEX FULL SCAN …..

In this case the group by operation simply groups the rows it does not do the sort operation as this has already been completed.

Sorts are expensive operations especially on large tables where the rows do not fit in memory and spill to disk. By default sort blocks are placed into the buffer cache. This may result in aging out of other blocks that may be reread by other processes. To avoid this you can use the parameter <Parameter:SORT_DIRECT_WRITES> which does not place sort blocks into the buffer cache.

Filter

Has a number of different meanings used to indicate partition elimination may also indicate an actual filter step where one row source is filtering another functions such as min may introduce filter steps into query plans

In this example there are 2 filter steps. The first is effectively like a NL except that it stops when it gets something that it doesn’t like (i.e. a bounded NL). This is there because of the not in. The second is filtering out the min value:

SQL> explain plan for select * from emp
     where empno not in (select min(empno)
     from big_emp group by empno);

Query Plan
——————
SELECT STATEMENT [CHOOSE]  Cost=1
  FILTER     **** This is like a bounded nested loops
    TABLE ACCESS FULL EMP [ANALYZED]
     FILTER   **** This filter is introduced by the min
        SORT GROUP BY NOSORT
          INDEX FULL SCAN BE_IX

This example is also interesting in that it has a NOSORT function. The group by does not need to sort because the index row source is already pre sorted.

Views

When a view cannot be merged into the main query you will often see a projection view operation. This indicates that the ‘view’ will be selected from directly as opposed to being broken down into joins on the base tables. A number of constructs make a view non mergeable. Inline views are also non mergeable.

In the following example the select contains an inline view which cannot be merged:

SQL> explain plan for
select ename,tot
from emp,
    (select empno,sum(empno) tot from big_emp group by empno) tmp
where emp.empno = tmp.empno;

Query Plan
————————
SELECT STATEMENT [CHOOSE]
  HASH JOIN
    TABLE ACCESS FULL EMP [ANALYZED]
    VIEW
      SORT GROUP BY
        INDEX FULL SCAN BE_IX

In this case the inline view tmp which contains an aggregate function cannot be merged into the main query. The explain plan shows this as a view step.

Partition Views

Allows a large table to be broken up into a number of smaller partitions which can be queried much more quickly than the table as a whole a union all view is built over the top to provide the original functionality Check constraints or where clauses provide partition elimination capabilities

SQL> explain plan for
select /*+ use_nl(p1,kbwyv1) ordered */  sum(prc_pd)
from parent1 p1,  kbwyv1
where p1.class = 22
and   kbwyv1.bitm_numb = p1.bitm_numb
and   kbwyv1.year = 1997
and   kbwyv1.week between 32 and 33 ;

Query Plan
—————————————–
SELECT STATEMENT   [FIRST_ROWS] Cost=1780
  SORT AGGREGATE
    NESTED LOOPS   [:Q65001] Ct=1780 Cd=40 Bt=3120
      TABLE ACCESS FULL PARENT1 [:Q65000] [AN] Ct=20 Cd=40 Bt=1040
      VIEW  KBWYV1 [:Q65001]
        UNION-ALL PARTITION  [:Q65001]
          FILTER   [:Q64000]
            TABLE ACCESS FULL KBWYT1 [AN] Ct=11 Cd=2000 Bt=104000
          TABLE ACCESS FULL KBWYT2 [AN] Ct=11 Cd=2000 Bt=104000
          TABLE ACCESS FULL KBWYT3 [AN] Ct=11 Cd=2000 Bt=104000
          FILTER   [:Q61000]
            TABLE ACCESS FULL KBWYT4 [AN] Ct=11 Cd=2000 Bt=104000

KBWYV1 is a view on 4 tables KBWYT1-4. KBWYT1-4 contain rows for week 31-34 respectively and are maintained by check constraints. This query should only return rows from partions 2 & 3. The filter operation indicates this. Partitions 1 & 4 are eliminated at execution time. The view line indicates that the view is not merged. The union-all partion information indicates that we have recognised this as a partition view. Note that the tables can be accessed in parallel.

Remote Queries

Only shows remote in the OPERATION column OTHER column shows query executed on remote node OTHER_NODE shows where it is executed Different operational characteristics for RBO & CBO

RBO – Drags everything across the link and joins locally
CBO – Uses cost estimates to determine whether to execute remotely or locally

SQL>  explain plan for
select *
from dept@loop_link;

Query Plan
——————————————————-
SELECT STATEMENT REMOTE  [CHOOSE] Cost=1
  TABLE ACCESS FULL DEPT [SJD.WORLD] [ANALYZED]

In this case the whole query has been sent to the remote site. The other column shows nothing.

SQL> explain plan for
select a.dname,avg(b.sal),max(b.sal)
from dept@loop_link a, emp b
where a.deptno=b.deptno
group by a.dname
order by max(b.sal),avg(b.sal) desc;

Query Plan
—————————————————–
SELECT STATEMENT   [CHOOSE] Cost=20
  SORT ORDER BY  [:Q137003] [PARALLEL_TO_SERIAL]
    SORT GROUP BY  [:Q137002] [PARALLEL_TO_PARALLEL]
      NESTED LOOPS   [:Q137001] [PARALLEL_TO_PARALLEL]
        REMOTE   [:Q137000] [PARALLEL_FROM_SERIAL]
        TABLE ACCESS FULL EMP [:Q137001] [ANALYZED]
        [PARALLEL_COMBINED_WITH_PARENT]

Bind Variables

Bind variables are recommended in most cases because they promote sharing of sql code
At parse time the parser has NO IDEA what the bind variable contains. With RBO this makes no difference but with CBO, which relies on accurate statistics to produce plans, this can be a problem.

Defining bind variables in sqlplus:

variable x varchar2(18);
assigning values:
begin
:x := ‘hello’;
end;
/

SQL> explain plan for
select *
from dept
where rowid = ‘:x’;

Query Plan
————————————
SELECT STATEMENT [CHOOSE] Cost=1
  TABLE ACCESS BY ROWID DEPT [ANALYZED]

Parallel Query

Main indicators that a query is using PQO:

  • [:Q1000004] entries in the explain plan
  • Checkout the other column for details of what the slaves are executing
  • v$pq_slave will show any parallel activity

Columns to look in for information

  • other – contains the query passed to the slaves
  • other_tag – describes the contents of other
  • object_node – indicates order of pqo slaves

Parallel Query operates on a producer/consumer basis. When you specify parallel degree 4 oracle tries to allocate 4 producer slaves and 4 consumer slaves. The producers can feed any of the consumers. If there are only 2 slaves available then we use these. If there is only 1 slave available then we go serial If there are none available then we use serial. If parallel_min_percent is set then we error ora 12827 instead of using a lower number of slaves or going serial

Consumer processes typically perform a sorting function. If there is no requirement for the data to be sorted then the consumer slaves are not produced and we end up with the number of slaves used matching the degree of parallelism as opposed to being 2x the degree.

Parallel Terms

PARALLEL_FROM_SERIAL This means that source of the data is serial but it is passed to a parallel consumer
PARALLEL_TO_PARALLEL Both the consumer and the producer are  parallel
PARALLEL_COMBINED_WITH_PARENT This operation has been combined with the parent operator. For example in a sort merge join the sort operations would be shown as PARALLEL_COMBINED_WITH_PARENT because the sort and the merge are handled as 1 operation.
PARALELL_TO_SERIAL The source of the data is parallel but it is passed to a serial consumer. This typically will happen at the top of the explain plan but could occur anywhere

Examples of parallel queries

Assumptions

OPTIMIZER_MODE = CHOOSE
DEPT is small compared to EMP
DEPT has an index (DEPT_INDX) on deptno column

Three examples are presented

Query #1:  Serial
Query #2:  Parallel
Query #3:  Parallel, with forced optimization to RULE and forced usage of DEPT_INDX

Sample Query #1 (Serial)

select A.dname, avg(B.sal), max(B.sal)
from  dept A, emp B
where A.deptno = B.deptno
group by A.dname
order by max(B.sal), avg(B.sal) desc;

Execution Plan #1 (Serial)

OBJECT_NAME                      OBJECT_NODE OTHER
——————————-  ———– ——-
SELECT STATEMENT
 SORT ORDER BY
   SORT GROUP BY
     MERGE JOIN
       SORT JOIN
         TABLE ACCESS FULL emp
       SORT JOIN
         TABLE ACCESS FULL dept

Notice that the object_node and other columns are empty

Sample Query #2 (Query #1 with parallel hints)

select /*+ parallel(B,4) parallel(A,4) */
A.dname, avg(B.sal), max(B.sal)
from  dept A, emp B
where A.deptno = B.deptno
group by A.dname
order by max(B.sal), avg(B.sal) desc;

Execution Plan #2  (Parallel)

OBJECT_NAME                      OBJECT_NODE OTHER
——————————-  ———– ——-
SELECT STATEMENT      Cost = ??
 SORT ORDER BY                   :Q55004     **[7]**
   SORT GROUP BY                 :Q55003     **[6]**
     MERGE JOIN                  :Q55002     **[5]**
       SORT JOIN                 :Q55002     **[4]**
         TABLE ACCESS FULL emp   :Q55001     **[2]**
       SORT JOIN                 :Q55002     **[3]**
         TABLE ACCESS FULL dept  :Q55000     **[1]**

Execution Plan #2  — OTHER column

**[1]**  (:Q55000) “PARALLEL_FROM_SERIAL”

Serial execution of SELECT DEPTNO, DNAME FROM DEPT

**[2]**  (:Q55001) “PARALLEL_TO_PARALLEL”

        SELECT /*+ ROWID(A1)*/
        A1.”DEPTNO” C0, A1.”SAL” C1
        FROM “EMP” A1
        WHERE ROWID BETWEEN :1 AND :2

**[3]**  (:Q55002) “PARALLEL_COMBINED_WITH_PARENT”
**[4]**  (:Q55002) “PARALLEL_COMBINED_WITH_PARENT”
**[5]**  (:Q55002) “PARALLEL_TO_PARALLEL”

        SELECT /*+ ORDERED USE_MERGE(A2)*/
        A2.C1 C0, A1.C1 C1
        FROM :Q55001 A1,:Q55000 A2
        WHERE A1.C0=A2.C0

**[6]**  (:Q55003) “PARALLEL_TO_PARALLEL”

        SELECT MAX(A1.C1) C0, AVG(A1.C1) C1, A1.C0 C2
        FROM :Q55002 A1
        GROUP BY A1.C0

**[7]**  (:Q55004) “PARALLEL_FROM_SERIAL”

        SELECT A1.C0 C0, A1.C1 C1, A1.C2 C2
        FROM :Q55003 A1
        ORDER BY A1.CO, A1.C1 DESC

Sample Query #3 (Query #2 with fudged hints)

select /*+ index(A dept_indx) parallel(B,4) parallel(A,4) */
      A.dname, avg(B.sal), max(B.sal)
from  dept A, emp B
where A.deptno = B.deptno
group by A.dname
order by max(B.sal), avg(B.sal) desc;

Execution Plan #3  (Parallel)

OBJECT_NAME                         OBJECT_NODE OTHER
———————————– ———– ——-
SELECT STATEMENT          Cost = ??
 SORT ORDER BY                      :Q58002     **[6]**
   SORT GROUP BY                    :Q58001     **[5]**
     NESTED LOOPS JOIN              :Q58000     **[4]**
       TABLE ACCESS FULL emp        :Q58000     **[3]**
       TABLE ACCESS BY ROWID dept   :Q58000     **[2]**
         INDEX RANGE SCAN dept_indx :Q58000     **[1]**

Execution Plan #3  — OTHER column

**[1]**  (:Q58000) “PARALLEL_COMBINED_WITH_PARENT”
**[2]**  (:Q58000) “PARALLEL_COMBINED_WITH_PARENT”
**[3]**  (:Q58000) “PARALLEL_COMBINED_WITH_PARENT”
**[4]**  (:Q58000) “PARALLEL_TO_PARALLEL”

        SELECT /*+ ORDERED USE_NL(A2) INDEX(A2) */
        A2.”DNAME” C0, A1.C0 C1
        FROM
          (SELECT /*+ ROWID(A3) */
           A3.”SAL” CO, A3.”DEPTNO” C1
           FROM “EMP” A3
           WHERE ROWID BETWEEN :1 AND :2) A1,
          “DEPT” A2
        WHERE A2.”DEPTNO” = A1.C1

**[5]**  (:Q58001) “PARALLEL_TO_PARALLEL”

        SELECT MAX(A1.C1) C0, AVG(A1.C1) C1, A1.C0 C2
        FROM :Q58000 A1
        GROUP BY A1.C0

**[6]**  (:Q58002) “PARALLEL_TO_SERIAL”

        SELECT A1.C0 C0, A1.C1 C1, A1.C2 C2
        FROM :Q58001 A1
        ORDER BY A1.C0, A1.C1 DESC

How to obtain explain plans

Explain plan for

Main advantage is that it does not actually run the query – just parses the sql. This means that it executes quickly. In the early stages of tuning explain plan gives you an idea of the potential performance of your query without actually running it. You can then make a judgement as to any modifications you may choose to make.

Autotrace

Autotrace can be configured to run the sql & gives a plan  and statistics afterwards or just give you an explain plan without execu

Zurück

  Interpreting Explain Plan 

What’s an explain plan?

An explain plan is a representation of the access path that is taken when a query is executed within Oracle.

Query processing can be divided into 7 phases:

[1] Syntactic Checks the syntax of the query
[2] Semantic Checks that all objects exist and are accessible
[3] View Merging Rewrites query as join on base tables as opposed to using views
[4] Statement
     Transformation
Rewrites query transforming some complex constructs into simpler ones where appropriate (e.g. subquery merging, in/or transformation)
[5] Optimization Determines the optimal access path for the query to take. With the Rule Based Optimizer (RBO) it uses a set of heuristics to determine access path. With the Cost Based Optimizer (CBO) we use statistics to analyze the relative costs of accessing objects.
[6] QEP Generation QEP = Query Evaluation Plan
[7] QEP Execution QEP = Query Evaluation Plan

Steps [1]-[6] are handled by the parser. Step [7] is the execution of the statement.

The explain plan is produced by the parser. Once the access path has been decided upon it is stored in the library cache together with the statement itself. We store queries in the library cache based upon a hashed representation  of that query. When looking for a statement in the library cache, we first apply a hashing algorithm to the statement and then we look for this hash value in the library cache. This access path will be used until the query is reparsed.

Terminology

Row Source A set of rows used in a query may be a select from a base object or the result set returned by joining 2 earlier row sources
Predicate where clause of a query
Tuples rows
Driving Table This is the row source that we use to seed the query. If this returns a lot of rows then this can have a negative affect on all subsequent operations
Probed Table This is the object we lookup data in after we have retrieved relevant key data from the driving table.

How does Oracle access data?

At the physical level Oracle reads blocks of data. The smallest amount of data read is a single Oracle block, the largest is constrained by operating system limits (and multiblock i/o). Logically Oracle finds the data to read by using the following methods:

  • Full Table Scan (FTS)
  • Index Lookup (unique & non-unique)
  • Rowid

Explain plan Hierarchy

Simple explain plan:

Query Plan
—————————————–
SELECT STATEMENT     [CHOOSE] Cost=1234
  TABLE ACCESS FULL LARGE [:Q65001] [ANALYZED]

The rightmost uppermost operation of an explain plan is the first thing that the explain plan will execute. In this case TABLE ACCESS FULL LARGE is the first operation. This statement means we are doing a full table scan of table LARGE. When this operation completes then the resultant row source is passed up to the
next level of the query for processing. In this case it is the SELECT STATEMENT which is the top of the query.

[CHOOSE] is an indication of the optimizer_goal for the query. This DOES NOT necessarily indicate that plan has actually used this goal. The only way to confirm this is to check the
cost= part of the explain plan as well. For example the following query indicates that the CBO has been used because there is a cost in the cost field:

SELECT STATEMENT     [CHOOSE] Cost=1234

However the explain plan below indicates the use of the RBO because the cost field is blank:

SELECT STATEMENT     [CHOOSE] Cost=

The cost field is a comparative cost that is used internally to determine the best cost for particular plans. The costs of different statements are not really directly comparable.

[:Q65001] indicates that this particular part of the query is being executed in parallel. This number indicates that the operation will be processed by a parallel query slave as opposed to being executed serially.

[ANALYZED] indicates that the object in question has been analyzed and there are currently statistics available for the CBO to use. There is no indication of the ‘level’ of analysis done.

Access Methods in detail

Full Table Scan (FTS)

In a FTS operation, the whole table is read up to the high water mark (HWM). The HWM marks the last block in the table that has ever had data written to it. If you have deleted all the rows then you will still read up to the HWM. Truncate resets the HWM back to the start of the table. FTS uses multiblock i/o to read the blocks from disk. Multiblock i/o is controlled by the parameter <PARAM:db_block_multi_block_read_count>.

This defaults to:

db_block_buffers / ( (PROCESSES+3) / 4 )

Maximum values are OS dependant

Buffers from FTS operations are placed on the Least Recently Used (LRU) end of the buffer cache so will be quickly aged out. FTS is not recommended for large tables unless you are reading >5-10% of it (or so) or you intend to run in parallel.

Example FTS explain plan:

SQL> explain plan for select * from dual;

Query Plan
—————————————–
SELECT STATEMENT     [CHOOSE] Cost=
  TABLE ACCESS FULL DUAL

Index lookup

Data is accessed by looking up key values in an index and returning rowids. A rowid uniquely identifies an individual row in a particular data block. This block is read via single block i/o.

In this example an index is used to find the relevant row(s) and then the table is accessed to lookup the ename column (which is not included in the index):

SQL> explain plan for
select empno,ename from emp where empno=10;
Query Plan

————————————
SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
    INDEX UNIQUE SCAN EMP_I1

Notice the ‘TABLE ACCESS BY ROWID’ section. This indicates that the table data is not being accessed via a FTS operation but rather by a rowid lookup. In this case the rowid has been produced by looking up values in the index first. The index is being accessed by an ‘INDEX UNIQUE SCAN’ operation. This is explained below. The index name in this case is EMP_I1. If all the required data resides in the index then a table lookup may be unnecessary and all you will see is an index access with no table access.

In the following example all the columns (empno) are in the index. Notice that no table access takes place:

SQL> explain plan for
select empno from emp where empno=10;

Query Plan
————————————
SELECT STATEMENT [CHOOSE] Cost=1
  INDEX UNIQUE SCAN EMP_I1

Indexes are presorted so sorting may be unecessary if the sort order required is the same as the index.

SQL> explain plan for select empno,ename from emp
where empno > 7876 order by empno;

Query Plan
————————————————————-
SELECT STATEMENT   [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
  INDEX RANGE SCAN EMP_I1 [ANALYZED]

In this case the index is sorted so ther rows will be returned in the order of the index hence a sort is unecessary.

SQL> explain plan for
select /*+ Full(emp) */ empno,ename from emp
where empno> 7876 order by empno;

Query Plan
————————————————————-
SELECT STATEMENT   [CHOOSE] Cost=9
  SORT ORDER BY
    TABLE ACCESS FULL EMP [ANALYZED]  Cost=1 Card=2 Bytes=66

Because we have forced a FTS the data is unsorted and so we must sort the data
after it has been retrieved.

There are 4 methods of index lookup:

  • index unique scan
  • index range scan
  • index full scan
  • index fast full scan

Index unique scan

Method for looking up a single key value via a unique index. Always returns a single value You must supply AT LEAST the leading column of the index to access data via the index, However this may return > 1 row as the uniqueness will not be guaranteed.

SQL> explain plan for
select empno,ename from emp where empno=10;

Query Plan
————————————
SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
    INDEX UNIQUE SCAN EMP_I1

Index range scan

Method for accessing multiple column values You must supply AT LEAST the leading column of the index to access data via the index Can be used for range operations (e.g. > < <> >= <= between)

SQL> explain plan for select empno,ename from emp
where empno > 7876 order by empno;

Query Plan
——————————————————-
SELECT STATEMENT   [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
  INDEX RANGE SCAN EMP_I1 [ANALYZED]

A non-unique index may return multiple values for the predicate col1 = 5 and will use an index range scan

SQL> explain plan for select mgr from emp where mgr = 5

Query plan
——————–
SELECT STATEMENT [CHOOSE] Cost=1
  INDEX RANGE SCAN EMP_I2 [ANALYZED]

Index Full Scan

In certain circumstances it is possible for the whole index to be scanned as opposed to a range scan (i.e. where no constraining predicates are provided for a table). Full index scans are  only available in the CBO as otherwise we are unable to determine whether a full scan would be a good idea or not. We choose an index Full Scan when we have statistics that indicate that it is going to be more efficient than a Full table scan and a sort.

For example we may do a Full index scan when we do an unbounded scan of an index and want the data to be ordered in the index order. The optimizer may decide that selecting all the information from the index and not sorting is more efficient than doing a FTS or a Fast Full Index Scan and then sorting.

An Index full scan will perform single block i/o’s and so it may prove to be inefficient. Index BE_IX is a concatenated index on big_emp (empno,ename)

SQL> explain plan for select empno,ename
     from big_emp order by empno,ename;

Query Plan
————————————————————
SELECT STATEMENT   [CHOOSE] Cost=26
  INDEX FULL SCAN BE_IX [ANALYZED]

Index Fast Full Scan

Scans all the block in the index Rows are not returned in sorted order Introduced in 7.3 and requires V733_PLANS_ENABLED=TRUE and CBO may be hinted using INDEX_FFS hint uses multiblock i/o can be executed in parallel can be used to access second column of concatenated indexes. This is because we are selecting all of the index.

Note that INDEX FAST FULL SCAN is the mechinism behind fast index create and recreate. Index BE_IX is a concatenated index on big_emp (empno,ename)

SQL> explain plan for select empno,ename from big_emp;

Query Plan
——————————————
SELECT STATEMENT   [CHOOSE] Cost=1
  INDEX FAST FULL SCAN BE_IX [ANALYZED]

Selecting the 2nd column of concatenated index:

SQL> explain plan for select ename from big_emp;

Query Plan
——————————————
SELECT STATEMENT   [CHOOSE] Cost=1
  INDEX FAST FULL SCAN BE_IX [ANALYZED]

Rowid

This is the quickest access method available Oracle simply retrieves the block specified and extracts the rows it is interested in. Most frequently seen in explain plans as Table access by Rowid

SQL> explain plan for select * from dept where rowid = ‘:x’;

Query Plan
————————————
SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID DEPT [ANALYZED]

Table is accessed by rowid following index lookup:

SQL> explain plan for
select empno,ename from emp where empno=10;

Query Plan
————————————
SELECT STATEMENT [CHOOSE] Cost=1
TABLE ACCESS BY ROWID EMP [ANALYZED]
    INDEX UNIQUE SCAN EMP_I1

Joins

A Join is a predicate that attempts to combine 2 row sources We only ever join 2 row sources together Join steps are always performed serially even though underlying row sources may have been accessed in parallel. Join order – order in which joins are performed

The join order makes a significant difference to the way in which the query is executed. By accessing particular row sources first, certain predicates may be satisfied that are not satisfied by with other join orders. This may prevent certain access paths from being taken.

Suppose there is a concatenated index on A(a.col1,a.col2). Note that a.col1 is the leading column. Consider the following query:

select A.col4
from   A,B,C
where  B.col3 = 10
and    A.col1 = B.col1
and    A.col2 = C.col2
and    C.col3 = 5

We could represent the joins present in the query using the following schematic:

  B     <—> A <—>    C
col3=10                col3=5

There are really only 2 ways we can drive the query: via B.col3 or C.col3. We would have to do a Full scan of A to be able to drive off it. This is unlikely to be efficient with large tables;

If we drive off table B, using predicate B.col3=10 (as a filter or lookup key) then we will retrieve the value for B.col1 and join to A.col1. Because we have now filled the leading column of the concatenated index on table A we can use this index to give us values for A.col2 and join to A.

However if we drive of table c, then we only get a value for a.col2 and since this is a trailing column of a concatenated index and the leading column has not been supplied at this point, we cannot use the index on a to lookup the data.

So it is likely that the best join order will be B A C. The CBO will obviously use costs to establish whether the individual access paths are a good idea or not.

If the CBO does not choose this join order then we can hint it by changing the from
clause to read:

from B,A,C

and using the /*+ ordered */ hint. The resultant query would be:

select /*+ ordered */ A.col4
from   B,A,C
where  B.col3 = 10
and    A.col1 = B.col1
and    A.col2 = C.col2
and    C.col3 = 5

Join Types

  • Sort Merge Join (SMJ)
  • Nested Loops (NL)
  • Hash Join

Sort Merge Join

Rows are produced by Row Source 1 and are then sorted Rows from Row Source 2 are then produced and sorted by the same sort key as Row Source 1. Row Source 1 and 2 are NOT accessed concurrently Sorted rows from both sides are then merged together (joined)

                   MERGE
                 /      \
            SORT        SORT
             |             |
        Row Source 1  Row Source 2

If the row sources are already (known to be) sorted then the sort operation is unecessary as long as both ’sides’ are sorted using the same key. Presorted row sources include indexed columns and row sources that have already been sorted in earlier steps. Although the merge of the 2 row sources is handled serially, the row sources could be accessed in parallel.

SQL> explain plan for
select /*+ ordered */ e.deptno,d.deptno
from emp e,dept d
where e.deptno = d.deptno
order by e.deptno,d.deptno;

Query Plan
————————————-
SELECT STATEMENT [CHOOSE] Cost=17
  MERGE JOIN
    SORT JOIN
      TABLE ACCESS FULL EMP [ANALYZED]
    SORT JOIN
      TABLE ACCESS FULL DEPT [ANALYZED]

Sorting is an expensive operation, especially with large tables. Because of this, SMJ is often not a particularly efficient join method.

Nested Loops

First we return all the rows from row source 1 Then we probe row source 2 once for each row returned from row source 1

Row source 1
~~~~~~~~~~~~
Row 1 ————–       — Probe ->       Row source 2
Row 2 ————–       — Probe ->       Row source 2
Row 3 ————–       — Probe ->       Row source 2

Row source 1 is known as the outer table
Row source 2 is known as the inner table

Accessing row source 2 is known a probing the inner table For nested loops to be efficient it is important that the first row source returns as few rows as possible as this directly controls the number of probes of the second row source. Also it helps if the access method for row source 2 is efficient as this operation is being repeated once for every row returned by row source 1.

SQL> explain plan for
select a.dname,b.sql
from dept a,emp b
where a.deptno = b.deptno;

Query Plan
————————-
SELECT STATEMENT [CHOOSE] Cost=5
  NESTED LOOPS
    TABLE ACCESS FULL DEPT [ANALYZED]
    TABLE ACCESS FULL EMP [ANALYZED]

Hash Join

New join type introduced in 7.3 More efficient in theory than NL & SMJ Only accessible via the CBO Smallest row source is chosen and used to build a hash table and a bitmap The second row source is hashed and checked against the hash table looking for joins. The bitmap is used as a quick lookup to check if rows are in the hash table and are especially useful when the hash table is too large to fit in memory.

SQL> explain plan for
select /*+ use_hash(emp) */ empno
from emp,dept
where emp.deptno = dept.deptno;

Query Plan
—————————-
SELECT STATEMENT  [CHOOSE] Cost=3
  HASH JOIN
    TABLE ACCESS FULL DEPT
    TABLE ACCESS FULL EMP

Hash joins are enabled by the parameter HASH_JOIN_ENABLED=TRUE in the init.ora or session. TRUE is the default in 7.3

Cartesian Product

A Cartesian Product is done where they are no join conditions between 2 row sources and there is no alternative method of accessing the data Not really a join as such as there is no join! Typically this is caused by a coding mistake where a join has been left out. It can be useful in some circumstances – Star joins uses cartesian products.

Notice that there is no join between the 2 tables:

SQL> explain plan for
select emp.deptno,dept,deptno
from emp,dept

Query Plan
——————————
SLECT STATEMENT [CHOOSE] Cost=5
  MERGE JOIN CARTESIAN
    TABLE ACCESS FULL DEPT
    SORT JOIN
      TABLE ACCESS FULL EMP

The CARTESIAN keyword indicate that we are doing a cartesian product.

Operations

Operations that show up in explain plans

  • sort
  • filter
  • view

Sorts

There are a number of different operations that promote sorts

  • order by clauses
  • group by
  • sort merge join

Note that if the row source is already appropriately sorted then no sorting is required. This is now indicated in 7.3:

SORT GROUP BY NOSORT
     INDEX FULL SCAN …..

In this case the group by operation simply groups the rows it does not do the sort operation as this has already been completed.

Sorts are expensive operations especially on large tables where the rows do not fit in memory and spill to disk. By default sort blocks are placed into the buffer cache. This may result in aging out of other blocks that may be reread by other processes. To avoid this you can use the parameter <Parameter:SORT_DIRECT_WRITES> which does not place sort blocks into the buffer cache.

Filter

Has a number of different meanings used to indicate partition elimination may also indicate an actual filter step where one row source is filtering another functions such as min may introduce filter steps into query plans

In this example there are 2 filter steps. The first is effectively like a NL except that it stops when it gets something that it doesn’t like (i.e. a bounded NL). This is there because of the not in. The second is filtering out the min value:

SQL> explain plan for select * from emp
     where empno not in (select min(empno)
     from big_emp group by empno);

Query Plan
——————
SELECT STATEMENT [CHOOSE]  Cost=1
  FILTER     **** This is like a bounded nested loops
    TABLE ACCESS FULL EMP [ANALYZED]
     FILTER   **** This filter is introduced by the min
        SORT GROUP BY NOSORT
          INDEX FULL SCAN BE_IX

This example is also interesting in that it has a NOSORT function. The group by does not need to sort because the index row source is already pre sorted.

Views

When a view cannot be merged into the main query you will often see a projection view operation. This indicates that the ‘view’ will be selected from directly as opposed to being broken down into joins on the base tables. A number of constructs make a view non mergeable. Inline views are also non mergeable.

In the following example the select contains an inline view which cannot be merged:

SQL> explain plan for
select ename,tot
from emp,
    (select empno,sum(empno) tot from big_emp group by empno) tmp
where emp.empno = tmp.empno;

Query Plan
————————
SELECT STATEMENT [CHOOSE]
  HASH JOIN
    TABLE ACCESS FULL EMP [ANALYZED]
    VIEW
      SORT GROUP BY
        INDEX FULL SCAN BE_IX

In this case the inline view tmp which contains an aggregate function cannot be merged into the main query. The explain plan shows this as a view step.

Partition Views

Allows a large table to be broken up into a number of smaller partitions which can be queried much more quickly than the table as a whole a union all view is built over the top to provide the original functionality Check constraints or where clauses provide partition elimination capabilities

SQL> explain plan for
select /*+ use_nl(p1,kbwyv1) ordered */  sum(prc_pd)
from parent1 p1,  kbwyv1
where p1.class = 22
and   kbwyv1.bitm_numb = p1.bitm_numb
and   kbwyv1.year = 1997
and   kbwyv1.week between 32 and 33 ;

Query Plan
—————————————–
SELECT STATEMENT   [FIRST_ROWS] Cost=1780
  SORT AGGREGATE
    NESTED LOOPS   [:Q65001] Ct=1780 Cd=40 Bt=3120
      TABLE ACCESS FULL PARENT1 [:Q65000] [AN] Ct=20 Cd=40 Bt=1040
      VIEW  KBWYV1 [:Q65001]
        UNION-ALL PARTITION  [:Q65001]
          FILTER   [:Q64000]
            TABLE ACCESS FULL KBWYT1 [AN] Ct=11 Cd=2000 Bt=104000
          TABLE ACCESS FULL KBWYT2 [AN] Ct=11 Cd=2000 Bt=104000
          TABLE ACCESS FULL KBWYT3 [AN] Ct=11 Cd=2000 Bt=104000
          FILTER   [:Q61000]
            TABLE ACCESS FULL KBWYT4 [AN] Ct=11 Cd=2000 Bt=104000

KBWYV1 is a view on 4 tables KBWYT1-4. KBWYT1-4 contain rows for week 31-34 respectively and are maintained by check constraints. This query should only return rows from partions 2 & 3. The filter operation indicates this. Partitions 1 & 4 are eliminated at execution time. The view line indicates that the view is not merged. The union-all partion information indicates that we have recognised this as a partition view. Note that the tables can be accessed in parallel.

Remote Queries

Only shows remote in the OPERATION column OTHER column shows query executed on remote node OTHER_NODE shows where it is executed Different operational characteristics for RBO & CBO

RBO – Drags everything across the link and joins locally
CBO – Uses cost estimates to determine whether to execute remotely or locally

SQL>  explain plan for
select *
from dept@loop_link;

Query Plan
——————————————————-
SELECT STATEMENT REMOTE  [CHOOSE] Cost=1
  TABLE ACCESS FULL DEPT [SJD.WORLD] [ANALYZED]

In this case the whole query has been sent to the remote site. The other column shows nothing.

SQL> explain plan for
select a.dname,avg(b.sal),max(b.sal)
from dept@loop_link a, emp b
where a.deptno=b.deptno
group by a.dname
order by max(b.sal),avg(b.sal) desc;

Query Plan
—————————————————–
SELECT STATEMENT   [CHOOSE] Cost=20
  SORT ORDER BY  [:Q137003] [PARALLEL_TO_SERIAL]
    SORT GROUP BY  [:Q137002] [PARALLEL_TO_PARALLEL]
      NESTED LOOPS   [:Q137001] [PARALLEL_TO_PARALLEL]
        REMOTE   [:Q137000] [PARALLEL_FROM_SERIAL]
        TABLE ACCESS FULL EMP [:Q137001] [ANALYZED]
        [PARALLEL_COMBINED_WITH_PARENT]

Bind Variables

Bind variables are recommended in most cases because they promote sharing of sql code
At parse time the parser has NO IDEA what the bind variable contains. With RBO this makes no difference but with CBO, which relies on accurate statistics to produce plans, this can be a problem.

Defining bind variables in sqlplus:

variable x varchar2(18);
assigning values:
begin
:x := ‘hello’;
end;
/

SQL> explain plan for
select *
from dept
where rowid = ‘:x’;

Query Plan
————————————
SELECT STATEMENT [CHOOSE] Cost=1
  TABLE ACCESS BY ROWID DEPT [ANALYZED]

Parallel Query

Main indicators that a query is using PQO:

  • [:Q1000004] entries in the explain plan
  • Checkout the other column for details of what the slaves are executing
  • v$pq_slave will show any parallel activity

Columns to look in for information

  • other – contains the query passed to the slaves
  • other_tag – describes the contents of other
  • object_node – indicates order of pqo slaves

Parallel Query operates on a producer/consumer basis. When you specify parallel degree 4 oracle tries to allocate 4 producer slaves and 4 consumer slaves. The producers can feed any of the consumers. If there are only 2 slaves available then we use these. If there is only 1 slave available then we go serial If there are none available then we use serial. If parallel_min_percent is set then we error ora 12827 instead of using a lower number of slaves or going serial

Consumer processes typically perform a sorting function. If there is no requirement for the data to be sorted then the consumer slaves are not produced and we end up with the number of slaves used matching the degree of parallelism as opposed to being 2x the degree.

Parallel Terms

PARALLEL_FROM_SERIAL This means that source of the data is serial but it is passed to a parallel consumer
PARALLEL_TO_PARALLEL Both the consumer and the producer are  parallel
PARALLEL_COMBINED_WITH_PARENT This operation has been combined with the parent operator. For example in a sort merge join the sort operations would be shown as PARALLEL_COMBINED_WITH_PARENT because the sort and the merge are handled as 1 operation.
PARALELL_TO_SERIAL The source of the data is parallel but it is passed to a serial consumer. This typically will happen at the top of the explain plan but could occur anywhere

Examples of parallel queries

Assumptions

OPTIMIZER_MODE = CHOOSE
DEPT is small compared to EMP
DEPT has an index (DEPT_INDX) on deptno column

Three examples are presented

Query #1:  Serial
Query #2:  Parallel
Query #3:  Parallel, with forced optimization to RULE and forced usage of DEPT_INDX

Sample Query #1 (Serial)

select A.dname, avg(B.sal), max(B.sal)
from  dept A, emp B
where A.deptno = B.deptno
group by A.dname
order by max(B.sal), avg(B.sal) desc;

Execution Plan #1 (Serial)

OBJECT_NAME                      OBJECT_NODE OTHER
——————————-  ———– ——-
SELECT STATEMENT
 SORT ORDER BY
   SORT GROUP BY
     MERGE JOIN
       SORT JOIN
         TABLE ACCESS FULL emp
       SORT JOIN
         TABLE ACCESS FULL dept

Notice that the object_node and other columns are empty

Sample Query #2 (Query #1 with parallel hints)

select /*+ parallel(B,4) parallel(A,4) */
A.dname, avg(B.sal), max(B.sal)
from  dept A, emp B
where A.deptno = B.deptno
group by A.dname
order by max(B.sal), avg(B.sal) desc;

Execution Plan #2  (Parallel)

OBJECT_NAME                      OBJECT_NODE OTHER
——————————-  ———– ——-
SELECT STATEMENT      Cost = ??
 SORT ORDER BY                   :Q55004     **[7]**
   SORT GROUP BY                 :Q55003     **[6]**
     MERGE JOIN                  :Q55002     **[5]**
       SORT JOIN                 :Q55002     **[4]**
         TABLE ACCESS FULL emp   :Q55001     **[2]**
       SORT JOIN                 :Q55002     **[3]**
         TABLE ACCESS FULL dept  :Q55000     **[1]**

Execution Plan #2  — OTHER column

**[1]**  (:Q55000) “PARALLEL_FROM_SERIAL”

Serial execution of SELECT DEPTNO, DNAME FROM DEPT

**[2]**  (:Q55001) “PARALLEL_TO_PARALLEL”

        SELECT /*+ ROWID(A1)*/
        A1.”DEPTNO” C0, A1.”SAL” C1
        FROM “EMP” A1
        WHERE ROWID BETWEEN :1 AND :2

**[3]**  (:Q55002) “PARALLEL_COMBINED_WITH_PARENT”
**[4]**  (:Q55002) “PARALLEL_COMBINED_WITH_PARENT”
**[5]**  (:Q55002) “PARALLEL_TO_PARALLEL”

        SELECT /*+ ORDERED USE_MERGE(A2)*/
        A2.C1 C0, A1.C1 C1
        FROM :Q55001 A1,:Q55000 A2
        WHERE A1.C0=A2.C0

**[6]**  (:Q55003) “PARALLEL_TO_PARALLEL”

        SELECT MAX(A1.C1) C0, AVG(A1.C1) C1, A1.C0 C2
        FROM :Q55002 A1
        GROUP BY A1.C0

**[7]**  (:Q55004) “PARALLEL_FROM_SERIAL”

        SELECT A1.C0 C0, A1.C1 C1, A1.C2 C2
        FROM :Q55003 A1
        ORDER BY A1.CO, A1.C1 DESC

Sample Query #3 (Query #2 with fudged hints)

select /*+ index(A dept_indx) parallel(B,4) parallel(A,4) */
      A.dname, avg(B.sal), max(B.sal)
from  dept A, emp B
where A.deptno = B.deptno
group by A.dname
order by max(B.sal), avg(B.sal) desc;

Execution Plan #3  (Parallel)

OBJECT_NAME                         OBJECT_NODE OTHER
———————————– ———– ——-
SELECT STATEMENT          Cost = ??
 SORT ORDER BY                      :Q58002     **[6]**
   SORT GROUP BY                    :Q58001     **[5]**
     NESTED LOOPS JOIN              :Q58000     **[4]**
       TABLE ACCESS FULL emp        :Q58000     **[3]**
       TABLE ACCESS BY ROWID dept   :Q58000     **[2]**
         INDEX RANGE SCAN dept_indx :Q58000     **[1]**

Execution Plan #3  — OTHER column

**[1]**  (:Q58000) “PARALLEL_COMBINED_WITH_PARENT”
**[2]**  (:Q58000) “PARALLEL_COMBINED_WITH_PARENT”
**[3]**  (:Q58000) “PARALLEL_COMBINED_WITH_PARENT”
**[4]**  (:Q58000) “PARALLEL_TO_PARALLEL”

        SELECT /*+ ORDERED USE_NL(A2) INDEX(A2) */
        A2.”DNAME” C0, A1.C0 C1
        FROM
          (SELECT /*+ ROWID(A3) */
           A3.”SAL” CO, A3.”DEPTNO” C1
           FROM “EMP” A3
           WHERE ROWID BETWEEN :1 AND :2) A1,
          “DEPT” A2
        WHERE A2.”DEPTNO” = A1.C1

**[5]**  (:Q58001) “PARALLEL_TO_PARALLEL”

        SELECT MAX(A1.C1) C0, AVG(A1.C1) C1, A1.C0 C2
        FROM :Q58000 A1
        GROUP BY A1.C0

**[6]**  (:Q58002) “PARALLEL_TO_SERIAL”

        SELECT A1.C0 C0, A1.C1 C1, A1.C2 C2
        FROM :Q58001 A1
        ORDER BY A1.C0, A1.C1 DESC

How to obtain explain plans

Explain plan for

Main advantage is that it does not actually run the query – just parses the sql. This means that it executes quickly. In the early stages of tuning explain plan gives you an idea of the potential performance of your query without actually running it. You can then make a judgement as to any modifications you may choose to make.

Autotrace

Autotrace can be configured to run the sql & gives a plan  and statistics afterwards or just give you an explain plan without executing the query.

Tkprof

Analyzes trace file

ting the query.

Tkprof

 

This article is from ; http://www.akadia.com/services/ora_interpreting_explain_plan.html

Analyzes trace file


Oracle Explain Plan

September 25, 2009

 

Oracle Explain Plan Terms:

 

Table Access Full: Oracle reads every row in selected table. In terms of that there is no primary key or index defined with the columns that you use at your where clause Oracle makes full table access.

OPERATION                      OPTIONS         OBJECT_NAME

—————————— ————— ——————–

SELECT STATEMENT

TABLE ACCESS                   FULL            Students

Selecting With Primary Keys:  Primary key defines a row uniquely. By using table’s primary key at where clause Oracle makes Index RowID Unique Scan   in order to select unique row which reduces our total cost so much.

OPERATION                      OPTIONS         OBJECT_NAME
------------------------------ --------------- --------------------
SELECT STATEMENT
TABLE ACCESS                   BY INDEX ROWID  Students
INDEX                          UNIQUE SCAN     Students _PK

 

Selecting With Ununique Indexes: Ununique indexes reduces the cost of full table scan. But, of course if we have change to use primary keys we should use them. If we can’t we can use other non-unique indexes. The reducement of cost varies due to index’s definition. If the uniqueness of our index columns raises retrieval time will go down. Because of this reason, use the criteria that will catch the fastest index for that query.

OPERATION                      OPTIONS         OBJECT_NAME

—————————— ————— ——————–

SELECT STATEMENT

TABLE ACCESS                   BY INDEX ROWID  Students

INDEX                          RANGE SCAN      Students_IDX1

 

Efficiency of Join Statements:  We should be very careful at writing join statements. The column you choose the join plays very important role here. The most important thing we have to consider at creating joins is using indexed columns at where clause. Let’s assume that there is a table “StudentMarks” keeping marks of students for some particular lesson.For example phisics. The statement following retrievs  all the marks of the students having the name “ENGİN”. StudentMarks table does not have any foreign key at student column. İts only index column is mark.

select s.name,s.surname,m.mark
  from StudentMarks m, Students s
 where s.name = ‘ENGİN’

   and s.id = m.studentid

   and m.mark between 10000 and 30000

 

OPERATION                      OPTIONS         OBJECT_NAME

—————————— ————— ——————–

SELECT STATEMENT

NESTED LOOPS

TABLE ACCESS                   BY INDEX ROWID  Students

INDEX                          RANGE SCAN      Student_IDX2

TABLE ACCESS                   BY INDEX ROWID  StudentMarks

INDEX                          RANGE SCAN      StudentMarks_IDX3

 

All the columns are catched by range scan.

 

Choosing The Fastest Index: Indexes varies by the mean of cost. To query with minimum cost, we have to keep in mind the table’s count of rows. We should always give our priority to most sized table by the mean of choosing where clauses. Let’s take an example to examine this furter; 

 

select s.name,s.surname,m.mark
  from StudentMarks m, Students s
 where s.name = ‘ENGİN’

   and s.id = m.studentid

   and m.mark between 10000 and 30000

 

 

 

 

Will produce this plan:

OPERATION                      OPTIONS         OBJECT_NAME

—————————— ————— ——————–

SELECT STATEMENT

NESTED LOOPS

TABLE ACCESS                   BY INDEX ROWID  Students

INDEX                          RANGE SCAN      Students_IDX2

TABLE ACCESS                   BY INDEX ROWID  StudentMarks

INDEX                          RANGE SCAN      StudentMarks _IDX3

Oracle, tries to determine whether students or studentsmarks table is the best to index first. At the term oracle can not decide, Oracle starts indexing at the order of right to left at from clause. Be careful about this query. It is the same with the one above. But, at this query Oracle starts indexing with StudentMarks table.

 select s.name,s.surname,m.mark
  from Students s, StudentMarks m
 where s.name = ‘ENGİN’

   and s.id = m.studentid

   and m.mark between 10000 and 30000

 

This query produces this plan:

OPERATION                      OPTIONS         OBJECT_NAME

—————————— ————— ——————–

SELECT STATEMENT

NESTED LOOPS

TABLE ACCESS                   BY INDEX ROWID  StudentMarks

INDEX                          RANGE SCAN      StudentMarks _IDX3

TABLE ACCESS                   BY INDEX ROWID  Students

INDEX                          RANGE SCAN      Students_IDX2

 

StudentMarks.mark is queried first because we told Oracle to do so.

 

 

 

Utilizing Multiple Column Indexes

Utilizing Multiple Column Indexes: Multiple Column indexes uses more than one column for indexing. In order to use that index we have to search for the first column before we search second column in the index. To get more efficient queries from that indexes we have to choose index criteria more uniquely. Unique columns are also indexes. It is the best way to use unique indexes to get one specific row.

Oracle Explan Plan Terms

Whenever you read or write data in Oracle, you do so by issuing an SQL statement. One of Oracle’s task when it receives such a statement is to build a query execution plan. An execution plan defines how Oracle finds or writes the data. For example, an important decision that Oracle has to take is if it uses indexes or not. And if there are more indexes, which of these is used. All this is contained in an execution plan.

If one wants to explore such an execution plan, Oracle provides the SQL statement EXPLAIN PLAN to determine this.

The general syntax of EXPLAIN PLAN is:

explain plan for your-precious-sql-statement;

 

If you do an EXPLAIN PLAN, Oracle will analyze the statment and fill a special table with the Execution plan for that statement. You can indicate which table has to be filled with the following SQL command:

explain plan into table_name for your-precious-sql-statement;

If you omit the INTO TABLE_NAME clause, Oracle fills a table named PLAN_TABLE by default.

 

Whenever you read or write data in Oracle, you do so by issuing an SQL statement. One of Oracle’s task when it receives such a statement is to build a query execution plan. An execution plan defines how Oracle finds or writes the data. For example, an important decision that Oracle has to take is if it uses indexes or not. And if there are more indexes, which of these is used. All this is contained in an execution plan.

If one wants to explore such an execution plan, Oracle provides the SQL statement EXPLAIN PLAN to determine this.

The general syntax of EXPLAIN PLAN is:

explain plan for your-precious-sql-statement;

If you do an EXPLAIN PLAN, Oracle will analyze the statment and fill a special table with the Execution plan for that statement. You can indicate which table has to be filled with the following SQL command:

explain plan into table_name for your-precious-sql-statement;

If you omit the INTO TABLE_NAME clause, Oracle fills a table named PLAN_TABLE by default.

The Plan Table

The plan table is the table that Oracle fills when you have it explain an execution plan for an SQL statement. You must make sure such a plan table exists. Oracle ships with the script UTLXPLAN.SQL which creates this table, named PLAN_TABLE (which is the default name used by EXPLAIN PLAN). If you like, however, you can choose any other name for the plan table, as long as you have been granted insert on it and it has all the fields as here.

The fields (attributes) within the plan table

Arguably, the most important fields within the plan table are operation, option, object_name, id, and parent_id. The pair operation and object_name define what operation would be done on (or with) object_name. If an operation has an id which other operations have as parent_id, it means the other operations feed their result to the parent.

 

Possible values for operation are:

  • DELETE STATEMENT
  • INSERT STATEMENT
  • SELECT STATEMENT
  • UPDATE STATEMENT
  • AND-EQUAL
  • CONNECT BY
  • CONCATENATION
  • COUNT
  • DOMAIN INDEX
  • FILTER
  • FIRST ROW
  • FOR UPDATE
  • HASH JOIN
  • INDEX
  • INLIST ITERATOR
  • INTERSECTION
  • MERGE JOIN
  • MINUS
  • NESTED LOOPS
  • PARTITION,
  • REMOTE
  • SEQUENCE
  • SORT
  • TABLE ACCESS
  • UNION
  • VIEW

 

 

Option tells more about how an operation would be done. For example, the operation TABLE ACCESS can have the options: FULL or BY ROWID or many others. Full in this case means, that the entire table is accessed (takes a long time if table is huge) whereas BY ROWID means, Oracle knows where (from which block) the rows are to be retrieved, which makes the time to access the table shorter.

dbms_xplan

As of 9i, dbms_xplan can be used to format the plan table.

Operations

The following table is used to demonstrate EXPLAIN PLAN:

create table test_for_ep (a number, b varchar2(100));

Now, let’s explain the plan for selecting everything on that table:

delete plan_table;

explain plan for select /*+ rule */ * from test_for_ep where a = 5;

 

Displaying the execution plan

In order to view the explained plan, we have to query the plan table:

select
  substr (lpad(' ', level-1) || operation || ' (' || options || ')',1,30 ) "Operation",
  object_name                                                              "Object"
from
  plan_table
start with id = 0
connect by prior;

This statement is a simplified version of utlxpls.sql. utlxpls.sql is a script that Oracle ships.

Here’s the output of the explain plan:

SELECT STATEMENT ()
 TABLE ACCESS (FULL)           TEST_FOR_EP

First, take a look at the indention: TABLE ACCESS is indented right. In an explain plan output, the more indented an operation is, the earlier it is executed. And the result of this operation (or operations, if more than one have are equally indented AND have the same parent) is then feeded to the parent operation. In this case, TABLE ACCESS is made first, and its result feeded to SELECT STATEMENT (which is not an actual operation). Note the FULL in paranthesis in TABLE ACCESS: this means that the entire table is accessed.

Btw, sql*plus automatically explains the plan for you if autotrace is enabled.

Now, let’s create an index on that table:

create index test_for_ep_ix on test_for_ep (a);

And do the same select statement again:

delete plan_table;
explain plan for select /*+ rule */ * from test_for_ep where a = 5;

The plan is now:

SELECT STATEMENT ()
 TABLE ACCESS (BY INDEX ROWID) TEST_FOR_EP
  INDEX (RANGE SCAN)           TEST_FOR_EP_IX

Obviously, the index (TEST_FOR_EP_IX) is used first (most indented) then used for a TABLE ACCESS, second most indented, then the result is returned. The table access is not done by a full table scan but rather by using the data’s rowid.

INDEX

In the last example, Oracle employed an INDEX (RANGE SCAN). The RANGE SCAN basically means, that the index was used, but that it can return more than one row. Now, we create a unique index to see how this alters the explain plan:

create table test_for_ep (a number, b varchar2(100), constraint uq_tp unique(a));
 
delete plan_table;
explain plan for select /*+ rule */ * from test_for_ep where a = 5;

The explained plan is:

SELECT STATEMENT ()
 TABLE ACCESS (BY INDEX ROWID) TEST_FOR_EP
  INDEX (UNIQUE SCAN)          UQ_TP

INDEX (UNIQUE SCAN) means, that this index is used, and it sort of guarantees that this index returnes exactly one rowid. What happens, if we query the field not for equality but for greater than (a>5)?

explain plan for select /*+ rule */ * from test_for_ep where a > 5;

Here, we see that the index is used, but for a RANGE SCAN:

SELECT STATEMENT ()
 TABLE ACCESS (BY INDEX ROWID) TEST_FOR_EP
  INDEX (RANGE SCAN)           UQ_TP

If we only query fields of a table that are already in an index, Oracle doesn’t have to read the data blocks because it can get the relevant data from the index:

create table test_for_ep (a number, b varchar2(100), constraint uq_tp unique(a));
 
delete plan_table;
explain plan for select /*+ rule */ a from test_for_ep where a > 5 and a < 50;

Here’s the query execution planexecution plan. No table access anymore!

SELECT STATEMENT ()
 INDEX (RANGE SCAN)            UQ_TP

MERGE JOIN

See here. The first table’s join key is ba while the second table’s join key is aa.

create table test_for_ep_a (aa number, ab varchar2(100));
create table test_for_ep_b (ba number, bb varchar2(100));

Note, there are no indexes on both of the tables. Now, we join the tables on aa and ba:

explain plan for
  select /*+ rule */ a.aa from test_for_ep_a a, test_for_ep_b b where
  a.aa=b.ba and a.aa > 5;

As there are no indexes, both tables must be TABLE ACCESSed (FULL). After these accesses, their results are sorted.

SELECT STATEMENT ()
 MERGE JOIN ()
  SORT (JOIN)
   TABLE ACCESS (FULL)         TEST_FOR_EP_B
  SORT (JOIN)
   TABLE ACCESS (FULL)         TEST_FOR_EP_A

Note MERGE JOINs can only be used for equi joins, as is demonstrated in NESTED LOOPS

 

NESTED LOOPS

For each relevant row in the first table (driving table), find all matching rows in the other table (probed table).

See also here.

create table test_for_ep_a (aa number, ab varchar2(100));
create table test_for_ep_b (ba number, bb varchar2(100));
explain plan for
  select /*+ rule */ a.aa from test_for_ep_a a, test_for_ep_b b where
  a.aa > b.ba and a.aa > 5;

Note, there is no equi join to join test_for_ep_a and test_for_ep_b, (a.aa > b.ba)

SELECT STATEMENT ()
 NESTED LOOPS ()
  TABLE ACCESS (FULL)          TEST_FOR_EP_B
  TABLE ACCESS (FULL)          TEST_FOR_EP_A

Now, we put an index on TEST_FOR_EP_B and see how that influences our nested loop:

create table test_for_ep_a (aa number, ab varchar2(100));
create table test_for_ep_b (ba number, bb varchar2(100), constraint uq_ba unique(ba));
 
delete plan_table;
explain plan for
  select /*+ rule */ a.aa from test_for_ep_a a, test_for_ep_b b where
  a.aa > b.ba;

The plan is:

SELECT STATEMENT ()
 NESTED LOOPS ()
  TABLE ACCESS (FULL)          TEST_FOR_EP_A
  INDEX (RANGE SCAN)           UQ_BA

Interpreted, this means: TEST_FOR_EP_A is fully accessed and for each row, TEST_FOR_EP_B (or more accurately, its index UQ_BA) is probed. Thinking about it, this makes sense, doing the costly TABLE ACCESS once and use the index for each row. Then again, thinking about it, if TEST_FOR_EP_A is very small nad TEST_FOR_EP_B is large, this doesn’t make sense anymore. This is when the Cost Based Optimizer comes into play.

Sorts

Aggregate Sorts

Whenever a result set must be sorted, the operation is sort. If this sort is used to return a single row (for example max or min) the options is AGGREGATE. Consider the following example:

create table t_ep (
  w date,
  v number,
  x varchar2(40)
);
 
 
delete plan_table;
explain plan for select /*+ rule */ max(w) from t_ep where v=4;
SELECT STATEMENT ()
 SORT (AGGREGATE)
  TABLE ACCESS (FULL)          T_EP

Now: creating an index:

alter table t_ep add constraint uq_t_ep unique(v);
delete plan_table;
explain plan for select /*+ rule */ max(w) from t_ep where v=4;
SELECT STATEMENT ()
 SORT (AGGREGATE)
  TABLE ACCESS (BY INDEX ROWID) T_EP
   INDEX (UNIQUE SCAN)          UQ_T_EP

TKPROF

If you want to know, how much time an SQL statement acutally used, use TKPROF

 

 

ReferencesTop of Form

 

-          http://www.evolt.org/node/2986

Adam Patrick, Use Oracle’s Explain Plan to Tune Your Queries, August 24, 2000

-          http://www.adp-gmbh.ch/ora/explainplan.html

 


Oracle Explain Plan

September 25, 2009

Oracle Explain Plan Terms:

Table Access Full: Oracle reads every row in selected table. In terms of that there is no primary key or index defined with the columns that you use at your where clause Oracle makes full table access.
OPERATION OPTIONS OBJECT_NAME
—————————— ————— ——————–
SELECT STATEMENT
TABLE ACCESS FULL Students
Selecting With Primary Keys: Primary key defines a row uniquely. By using table’s primary key at where clause Oracle makes Index RowID Unique Scan in order to select unique row which reduces our total cost so much.
OPERATION OPTIONS OBJECT_NAME
—————————— ————— ——————–
SELECT STATEMENT
TABLE ACCESS BY INDEX ROWID Students
INDEX UNIQUE SCAN Students _PK

Selecting With Ununique Indexes: Ununique indexes reduces the cost of full table scan. But, of course if we have change to use primary keys we should use them. If we can’t we can use other non-unique indexes. The reducement of cost varies due to index’s definition. If the uniqueness of our index columns raises retrieval time will go down. Because of this reason, use the criteria that will catch the fastest index for that query.
OPERATION OPTIONS OBJECT_NAME
—————————— ————— ——————–
SELECT STATEMENT
TABLE ACCESS BY INDEX ROWID Students
INDEX RANGE SCAN Students_IDX1

Efficiency of Join Statements: We should be very careful at writing join statements. The column you choose the join plays very important role here. The most important thing we have to consider at creating joins is using indexed columns at where clause. Let’s assume that there is a table “StudentMarks” keeping marks of students for some particular lesson.For example phisics. The statement following retrievs all the marks of the students having the name “ENGİN”. StudentMarks table does not have any foreign key at student column. İts only index column is mark.
select s.name,s.surname,m.mark
from StudentMarks m, Students s
where s.name = ‘ENGİN’
and s.id = m.studentid
and m.mark between 10000 and 30000

OPERATION OPTIONS OBJECT_NAME
—————————— ————— ——————–
SELECT STATEMENT
NESTED LOOPS
TABLE ACCESS BY INDEX ROWID Students
INDEX RANGE SCAN Student_IDX2
TABLE ACCESS BY INDEX ROWID StudentMarks
INDEX RANGE SCAN StudentMarks_IDX3

All the columns are catched by range scan.

Choosing The Fastest Index: Indexes varies by the mean of cost. To query with minimum cost, we have to keep in mind the table’s count of rows. We should always give our priority to most sized table by the mean of choosing where clauses. Let’s take an example to examine this furter;

select s.name,s.surname,m.mark
from StudentMarks m, Students s
where s.name = ‘ENGİN’
and s.id = m.studentid
and m.mark between 10000 and 30000

Will produce this plan:
OPERATION OPTIONS OBJECT_NAME
—————————— ————— ——————–
SELECT STATEMENT
NESTED LOOPS
TABLE ACCESS BY INDEX ROWID Students
INDEX RANGE SCAN Students_IDX2
TABLE ACCESS BY INDEX ROWID StudentMarks
INDEX RANGE SCAN StudentMarks _IDX3
Oracle, tries to determine whether students or studentsmarks table is the best to index first. At the term oracle can not decide, Oracle starts indexing at the order of right to left at from clause. Be careful about this query. It is the same with the one above. But, at this query Oracle starts indexing with StudentMarks table.
select s.name,s.surname,m.mark
from Students s, StudentMarks m
where s.name = ‘ENGİN’
and s.id = m.studentid
and m.mark between 10000 and 30000

This query produces this plan:
OPERATION OPTIONS OBJECT_NAME
—————————— ————— ——————–
SELECT STATEMENT
NESTED LOOPS
TABLE ACCESS BY INDEX ROWID StudentMarks
INDEX RANGE SCAN StudentMarks _IDX3
TABLE ACCESS BY INDEX ROWID Students
INDEX RANGE SCAN Students_IDX2

StudentMarks.mark is queried first because we told Oracle to do so.

Utilizing Multiple Column Indexes
Utilizing Multiple Column Indexes: Multiple Column indexes uses more than one column for indexing. In order to use that index we have to search for the first column before we search second column in the index. To get more efficient queries from that indexes we have to choose index criteria more uniquely. Unique columns are also indexes. It is the best way to use unique indexes to get one specific row.
Oracle Explan Plan Terms
Whenever you read or write data in Oracle, you do so by issuing an SQL statement. One of Oracle’s task when it receives such a statement is to build a query execution plan. An execution plan defines how Oracle finds or writes the data. For example, an important decision that Oracle has to take is if it uses indexes or not. And if there are more indexes, which of these is used. All this is contained in an execution plan.
If one wants to explore such an execution plan, Oracle provides the SQL statement EXPLAIN PLAN to determine this.
The general syntax of EXPLAIN PLAN is:
explain plan for your-precious-sql-statement;

If you do an EXPLAIN PLAN, Oracle will analyze the statment and fill a special table with the Execution plan for that statement. You can indicate which table has to be filled with the following SQL command:
explain plan into table_name for your-precious-sql-statement;
If you omit the INTO TABLE_NAME clause, Oracle fills a table named PLAN_TABLE by default.

Whenever you read or write data in Oracle, you do so by issuing an SQL statement. One of Oracle’s task when it receives such a statement is to build a query execution plan. An execution plan defines how Oracle finds or writes the data. For example, an important decision that Oracle has to take is if it uses indexes or not. And if there are more indexes, which of these is used. All this is contained in an execution plan.
If one wants to explore such an execution plan, Oracle provides the SQL statement EXPLAIN PLAN to determine this.
The general syntax of EXPLAIN PLAN is:
explain plan for your-precious-sql-statement;
If you do an EXPLAIN PLAN, Oracle will analyze the statment and fill a special table with the Execution plan for that statement. You can indicate which table has to be filled with the following SQL command:
explain plan into table_name for your-precious-sql-statement;
If you omit the INTO TABLE_NAME clause, Oracle fills a table named PLAN_TABLE by default.
The Plan Table
The plan table is the table that Oracle fills when you have it explain an execution plan for an SQL statement. You must make sure such a plan table exists. Oracle ships with the script UTLXPLAN.SQL which creates this table, named PLAN_TABLE (which is the default name used by EXPLAIN PLAN). If you like, however, you can choose any other name for the plan table, as long as you have been granted insert on it and it has all the fields as here.
The fields (attributes) within the plan table
Arguably, the most important fields within the plan table are operation, option, object_name, id, and parent_id. The pair operation and object_name define what operation would be done on (or with) object_name. If an operation has an id which other operations have as parent_id, it means the other operations feed their result to the parent.

Possible values for operation are:
• DELETE STATEMENT
• INSERT STATEMENT
• SELECT STATEMENT
• UPDATE STATEMENT
• AND-EQUAL
• CONNECT BY
• CONCATENATION
• COUNT
• DOMAIN INDEX
• FILTER
• FIRST ROW
• FOR UPDATE
• HASH JOIN
• INDEX
• INLIST ITERATOR
• INTERSECTION
• MERGE JOIN
• MINUS
• NESTED LOOPS
• PARTITION,
• REMOTE
• SEQUENCE
• SORT
• TABLE ACCESS
• UNION
• VIEW

Option tells more about how an operation would be done. For example, the operation TABLE ACCESS can have the options: FULL or BY ROWID or many others. Full in this case means, that the entire table is accessed (takes a long time if table is huge) whereas BY ROWID means, Oracle knows where (from which block) the rows are to be retrieved, which makes the time to access the table shorter.
dbms_xplan
As of 9i, dbms_xplan can be used to format the plan table.
Operations
The following table is used to demonstrate EXPLAIN PLAN:
create table test_for_ep (a number, b varchar2(100));
Now, let’s explain the plan for selecting everything on that table:
delete plan_table;
explain plan for select /*+ rule */ * from test_for_ep where a = 5;

Displaying the execution plan
In order to view the explained plan, we have to query the plan table:
select
substr (lpad(‘ ‘, level-1) || operation || ‘ (‘ || options || ‘)’,1,30 ) “Operation”,
object_name “Object”
from
plan_table
start with id = 0
connect by prior id=parent_id;
This statement is a simplified version of utlxpls.sql. utlxpls.sql is a script that Oracle ships.
Here’s the output of the explain plan:
SELECT STATEMENT ()
TABLE ACCESS (FULL) TEST_FOR_EP
First, take a look at the indention: TABLE ACCESS is indented right. In an explain plan output, the more indented an operation is, the earlier it is executed. And the result of this operation (or operations, if more than one have are equally indented AND have the same parent) is then feeded to the parent operation. In this case, TABLE ACCESS is made first, and its result feeded to SELECT STATEMENT (which is not an actual operation). Note the FULL in paranthesis in TABLE ACCESS: this means that the entire table is accessed.
Btw, sql*plus automatically explains the plan for you if autotrace is enabled.
Now, let’s create an index on that table:
create index test_for_ep_ix on test_for_ep (a);
And do the same select statement again:
delete plan_table;
explain plan for select /*+ rule */ * from test_for_ep where a = 5;
The plan is now:
SELECT STATEMENT ()
TABLE ACCESS (BY INDEX ROWID) TEST_FOR_EP
INDEX (RANGE SCAN) TEST_FOR_EP_IX
Obviously, the index (TEST_FOR_EP_IX) is used first (most indented) then used for a TABLE ACCESS, second most indented, then the result is returned. The table access is not done by a full table scan but rather by using the data’s rowid.
INDEX
In the last example, Oracle employed an INDEX (RANGE SCAN). The RANGE SCAN basically means, that the index was used, but that it can return more than one row. Now, we create a unique index to see how this alters the explain plan:
create table test_for_ep (a number, b varchar2(100), constraint uq_tp unique(a));

delete plan_table;
explain plan for select /*+ rule */ * from test_for_ep where a = 5;
The explained plan is:
SELECT STATEMENT ()
TABLE ACCESS (BY INDEX ROWID) TEST_FOR_EP
INDEX (UNIQUE SCAN) UQ_TP
INDEX (UNIQUE SCAN) means, that this index is used, and it sort of guarantees that this index returnes exactly one rowid. What happens, if we query the field not for equality but for greater than (a>5)?
explain plan for select /*+ rule */ * from test_for_ep where a > 5;
Here, we see that the index is used, but for a RANGE SCAN:
SELECT STATEMENT ()
TABLE ACCESS (BY INDEX ROWID) TEST_FOR_EP
INDEX (RANGE SCAN) UQ_TP
If we only query fields of a table that are already in an index, Oracle doesn’t have to read the data blocks because it can get the relevant data from the index:
create table test_for_ep (a number, b varchar2(100), constraint uq_tp unique(a));

delete plan_table;
explain plan for select /*+ rule */ a from test_for_ep where a > 5 and a 5;
As there are no indexes, both tables must be TABLE ACCESSed (FULL). After these accesses, their results are sorted.
SELECT STATEMENT ()
MERGE JOIN ()
SORT (JOIN)
TABLE ACCESS (FULL) TEST_FOR_EP_B
SORT (JOIN)
TABLE ACCESS (FULL) TEST_FOR_EP_A
Note MERGE JOINs can only be used for equi joins, as is demonstrated in NESTED LOOPS

NESTED LOOPS
For each relevant row in the first table (driving table), find all matching rows in the other table (probed table).
See also here.
create table test_for_ep_a (aa number, ab varchar2(100));
create table test_for_ep_b (ba number, bb varchar2(100));
explain plan for
select /*+ rule */ a.aa from test_for_ep_a a, test_for_ep_b b where
a.aa > b.ba and a.aa > 5;
Note, there is no equi join to join test_for_ep_a and test_for_ep_b, (a.aa > b.ba)
SELECT STATEMENT ()
NESTED LOOPS ()
TABLE ACCESS (FULL) TEST_FOR_EP_B
TABLE ACCESS (FULL) TEST_FOR_EP_A
Now, we put an index on TEST_FOR_EP_B and see how that influences our nested loop:
create table test_for_ep_a (aa number, ab varchar2(100));
create table test_for_ep_b (ba number, bb varchar2(100), constraint uq_ba unique(ba));

delete plan_table;
explain plan for
select /*+ rule */ a.aa from test_for_ep_a a, test_for_ep_b b where
a.aa > b.ba;
The plan is:
SELECT STATEMENT ()
NESTED LOOPS ()
TABLE ACCESS (FULL) TEST_FOR_EP_A
INDEX (RANGE SCAN) UQ_BA
Interpreted, this means: TEST_FOR_EP_A is fully accessed and for each row, TEST_FOR_EP_B (or more accurately, its index UQ_BA) is probed. Thinking about it, this makes sense, doing the costly TABLE ACCESS once and use the index for each row. Then again, thinking about it, if TEST_FOR_EP_A is very small nad TEST_FOR_EP_B is large, this doesn’t make sense anymore. This is when the Cost Based Optimizer comes into play.
Sorts
Aggregate Sorts
Whenever a result set must be sorted, the operation is sort. If this sort is used to return a single row (for example max or min) the options is AGGREGATE. Consider the following example:
create table t_ep (
w date,
v number,
x varchar2(40)
);

delete plan_table;
explain plan for select /*+ rule */ max(w) from t_ep where v=4;
SELECT STATEMENT ()
SORT (AGGREGATE)
TABLE ACCESS (FULL) T_EP
Now: creating an index:
alter table t_ep add constraint uq_t_ep unique(v);
delete plan_table;
explain plan for select /*+ rule */ max(w) from t_ep where v=4;
SELECT STATEMENT ()
SORT (AGGREGATE)
TABLE ACCESS (BY INDEX ROWID) T_EP
INDEX (UNIQUE SCAN) UQ_T_EP
TKPROF
If you want to know, how much time an SQL statement acutally used, use TKPROF

References

- http://www.evolt.org/node/2986
Adam Patrick, Use Oracle’s Explain Plan to Tune Your Queries, August 24, 2000
- http://www.adp-gmbh.ch/ora/explainplan.html


Execute Immediate

August 14, 2009

EXECUTE IMMEDIATE StatementThe EXECUTE IMMEDIATE statement executes a dynamic SQL statement or anonymous PL/SQL block. You can use it to issue SQL statements that cannot be represented directly in PL/SQL, or to build up statements where you do not know all the table names, WHERE clauses, and so on in advance. For more information, see “Using the EXECUTE IMMEDIATE Statement in PL/SQL”.

Syntax

Description of the illustration execute_immediate_statement.gif

Keyword and Parameter Description

bind_argument

An expression whose value is passed to the dynamic SQL statement, or a variable that stores a value returned by the dynamic SQL statement.

BULK COLLECT

Stores result values in one or more collections, for faster queries than loops with FETCH statements. For more information, see “Reducing Loop Overhead for DML Statements and Queries with Bulk SQL”.

collection_name

A declared collection into which select_item values are fetched. For each select_item, there must be a corresponding, type-compatible collection in the list.

host_array_name

An array (declared in a PL/SQL host environment and passed to PL/SQL as a bind variable) into which select_item values are fetched. For each select_item, there must be a corresponding, type-compatible array in the list. Host arrays must be prefixed with a colon.

define_variable

A variable that stores a selected column value.

dynamic_string

A string literal, variable, or expression that represents a single SQL statement or a PL/SQL block. It must be of type CHAR or VARCHAR2, not NCHAR or NVARCHAR2.

INTO …

Used only for single-row queries, this clause specifies the variables or record into which column values are retrieved. For each value retrieved by the query, there must be a corresponding, type-compatible variable or field in the INTO clause.

record_name

A user-defined or %ROWTYPE record that stores a selected row.

returning_clause

Returns values from inserted rows, eliminating the need to SELECT the rows afterward. You can retrieve the column values into variables or into collections. You cannot use the RETURNING clause for remote or parallel inserts. If the statement does not affect any rows, the values of the variables specified in the RETURNING clause are undefined. For the syntax of returning_clause, see the “RETURNING INTO Clause”.

USING …

Specifies a list of input and/or output bind arguments. The parameter mode defaults to IN.

Usage Notes

Except for multi-row queries, the dynamic string can contain any SQL statement (without the final semicolon) or any PL/SQL block (with the final semicolon). The string can also contain placeholders for bind arguments. You cannot use bind arguments to pass the names of schema objects to a dynamic SQL statement.

You can place all bind arguments in the USING clause. The default parameter mode is IN. For DML statements that have a RETURNING clause, you can place OUT arguments in the RETURNING INTO clause without specifying the parameter mode, which, by definition, is OUT. If you use both the USING clause and the RETURNING INTO clause, the USING clause can contain only IN arguments.

At run time, bind arguments replace corresponding placeholders in the dynamic string. Every placeholder must be associated with a bind argument in the USING clause and/or RETURNING INTO clause. You can use numeric, character, and string literals as bind arguments, but you cannot use Boolean literals (TRUE, FALSE, and NULL). To pass nulls to the dynamic string, you must use a workaround. See “Passing Nulls to Dynamic SQL”.

Dynamic SQL supports all the SQL datatypes. For example, define variables and bind arguments can be collections, LOBs, instances of an object type, and refs. Dynamic SQL does not support PL/SQL-specific types. For example, define variables and bind arguments cannot be BOOLEANs or index-by tables. The only exception is that a PL/SQL record can appear in the INTO clause.

You can execute a dynamic SQL statement repeatedly using new values for the bind arguments. You still incur some overhead, because EXECUTE IMMEDIATE re-prepares the dynamic string before every execution.

The string argument to the EXECUTE IMMEDIATE command cannot be one of the national character types, such as NCHAR or NVARCHAR2.


Using Java At Oracle DB

July 29, 2009

Oracle has presented us so many libraries that we can use in order to accomplish our tasks. But, sometimes you need more. Because of this reason Oracle give Java support. You can use your Java classes at Oracle pl/sql scripts. As an example please look at following code sections;

Giving Grants;
Firstly, you have to give Java privilidges to your user.

GRANT JAVASYSPRIV TO SOMEUSERNAME;
GRANT JAVAUSERPRIV TO SOMEUSERNAME;

Creating Java Class;

Then after you have to write your java code at DB on Java section.

create or replace and compile java source named engin as
public class deneme
{
public static String entry(String x)
{
return “engin_” + x;
}
}

Registering Java Class

This code registers our Java Class function deneme.entry as firstjava on pl/sql

CREATE OR REPLACE FUNCTION firstjava (
file IN VARCHAR2) RETURN VARCHAR2
AS LANGUAGE JAVA
NAME ‘deneme.entry(java.lang.String)
return java.lang.String’;

Example Procedure

CREATE OR REPLACE Procedure engin_tesst
aa varchar2(100);
IS
begin
aa:=firstjava(‘c:\temp\temp.sql’);
dbms_output.put_line(aa);
END;

Test Script

begin
engin_tesst;
end;

Result: c:\temp\temp.sqlaaa


INTRODUCTION TO J2ME

July 20, 2009

What is J2ME?

J2ME stands for Java 2, Micro Edition. It is a stripped-down version of Java targeted at devices which have limited processing power and storage capabilities and intermittent or fairly low-bandwidth network connections. These include mobile phones, pagers,wireless devices and set-top boxes among others.

A Sample Wireless Stack would consist of:

  • Profiles
  • Configurations
  • Java Virtual Machines
  • Host Operating System

What is a J2ME Configuration?

A configuration defines the minimum Java technology that an application developer can expect on a broad range of implementing devices.

J2ME Connected, Limited Device Configuration (CLDC)

  • specifies the Java environment for mobile phone, pager and wireless devices
  • CLDC devices are usually wireless
  • 160 – 512k of memory available for Java
  • typically has limited power or battery operated
  • network connectivity, often wireless, intermittent, low-bandwidth (9600bps or less)

J2ME Connected Device Configuration (CDC)

  • describes the Java environment for digital television set-top boxes, high end wireless devices and automotive telematics systems.
  • device is powered by a 32-bit processor
  • 2MB or more of total memory available for Java
  • network connectivity, often wireless, intermittent, low-bandwidth (9600bps or less)

These two configurations differ only in their respective memory and display capabilities.

What is a J2ME Profile?

A specification layer above the configuration which describes the Java configuration for a specific vertical market or device type.

J2ME Profiles

J2ME Mobile Information Device Profile (MIDP)

  • this is the application environment for wireless devices based on the CLDC
  • contains classes for user interface, storage and networking

J2ME Foundation Profile, Personal Basis, Personal and RMI profiles

  • these are profiles for devices based on the CDC, which are not addressed in this tutorial

Virtual Machines

The CLDC and the CDC each require their own virtual machine because of their different memory and display capabilities. The CLDC virtual machine is far smaller than that required by the CDC and supports less features. The virtual machine for the CLDC is called the Kilo Virtual Machine (KVM) and the virtual machine for the CDC is called the CVM.

Tools

 

First make sure that you have the Java 2 SDK, Standard Edition (J2SE SDK), version 1.4.2 (or later). This is essential for development. If you haven’t installed it, download it and install it from here http://java.sun.com/j2se/downloads/index.html.
You absolutely MUST have the J2SE SDK installed before you install the Java Wireless Toolkit as you will be needing the tools it contains (such as javac) to compile and run your MIDlets.

Then download the J2ME Wireless Toolkit (WTK) which is available free from Sun here – http://java.sun.com/products/j2mewtoolkit/. I’m going to assume that you’ll be installing this in the C:\j2mewtk\ directory, if you use another directory, just modify the paths accordingly.

Paths

Java needs to know where all your files are, so we need to add the location of the Java binaries to the system path.

Windows 95/98

Go to Start->Run. Type in command. Then type

SET PATH=%PATH%;C:\j2mewtk\bin

You should also edit your C:\autoexec.bat file to include this line, so you don’t have to enter it every single time you restart your computer. After you’ve done this, you should be able to run the tools included in the Java Wireless Toolkit from any directory on your system.

Windows 2000/XP

  • Go to Control Panel -> System.
  • Click on the Advanced Tab
  • Click on the Environment Variables button
  • Double-click the PATH variable in the System variables box
  • At the end of the Variable value field, add the path to your J2ME WTK installation – for me this is something like C:\j2mewtk
  • If you had to install the J2SE SDK too, it’s a good idea to add the path for that – for me this is C:\j2sdk1.4.2_03 and C:\j2sdk1.4.2_03\bin. Here’s what my screen looked like.

A good way to test if this worked is to type the preverify command without any arguments in the command line. You should see something like this on your screen.

C:\> preverify
Usage: PREVERIFY.EXE [options] classnames|dirnames …

where options include:
-classpath
Directories in which to look for classes
-d Directory in which output is written
@ Read command line arguments from a text file.

 

Application Development

MIDlets vs Applets

MIDlets are applets for mobile phones. Just like applets, they run in a protected sandbox – the KVM – but unlike applets, they are extremely limited. MIDP 1.0 is currently found on most Java-capable phones and is fairly restrictive. As an example – the KVM doesn’t allow you to process floating point numbers yet and MIDlets written for MIDP 1.0 can’t access anything outside of the sandbox without proprietary APIs from phone manufacturers. So, put your dreams of developing the ultimate MIDlet with hooks into every part of your phone OS on the backburner for a while. If you want to find out exactly how limited MIDP 1.0 is, you should probably read the spec here. Once you’ve done that you might want to check out  with that spec. For the time being we’re going to write our first MIDlet – a full-featured “Hello MIDlet” application.

Simple HelloMIDlet

We’re going to use a program called Ktoolbar from the JAVA WTK which we installed earlier.

  • Go to Start->Programs->J2ME Wireless Toolkit 2.1->KToolbar.
  • Click on the New Project button and name your project HelloProject and your MIDlet HelloMidlet. You should see something like this.
  • Once you press Create Project, KToolbar will create a bunch of directories for your project in the apps subdirectory. We’re going to ignore most of them for the moment and focus on a few important onesC:\j2mewtk\apps\HelloProject - the main directory for your project
    C:\j2mewtk\apps\HelloProject\bin - where Ktoolbar stores .jar, .jar and manifest.mf files
    C:\j2mewtk\apps\HelloProject\classes - where the class files are stored
    C:\j2mewtk\apps\HelloProject\src - where the source .java files are stored
  • Now, fire up your favourite text editor – I like Textpad- and type in the following code/* Hello Midlet – your first program*/
    import javax.microedition.lcdui.*;
    import javax.microedition.midlet.*;public class HelloMidlet
    extends MIDlet
    implements CommandListener {
    private Form mMainForm;

    public HelloMidlet() {
    mMainForm = new Form(“HelloMidlet”);
    mMainForm.append(new StringItem(null, “Hello, MIDP! \n\nYou and me – we’re gonna make sweet MIDlets together! “));
    mMainForm.addCommand(new Command(“Exit”, Command.EXIT, 0));
    mMainForm.setCommandListener(this);
    }

    public void startApp() {
    Display.getDisplay(this).setCurrent(mMainForm);
    }

    public void pauseApp() {}

    public void destroyApp(boolean unconditional) {}

    public void commandAction(Command c, Displayable s) {
    notifyDestroyed();
    }
    }

  • Save this file as HelloMidlet.java in the C:\j2mewtk\apps\HelloProject\src
  • Go back to KToolBar – then click on Build and then Run – you should see something like this.
  • Click on the Launch softkey in the emulator to get your MIDlet to say hello. You’ve just written your first MIDlet!

 

Provisioning

Okay, now how do I get my code onto my phone?

Once you’ve created your lovely little MIDlet and ensured that everything worked smoothly in the emulator, the next step is to get it running on an actual device. Provisioning is the name given to the process of deploying your application in such a way that it is easily downloaded and installed on the device.

1. Over The Air (OTA) Provisioning

OTA provisioning allows users to download your application wirelessly using the WAP browsers built into their phones. To begin, we need to take a look at the Java Application Descriptor (JAD) file that is created when you package a MIDlet using the J2ME Wireless Toolkit. The JAD file stores information about your application and lets you modify various parameters of the MIDlet suite such as where the icon resource can be found, which MIDlets are included and where you can download the full version of the application. To edit a JAD file using the Wireless Toolkit, open your project, then click on Settings. This will open up a new window with a number of tabs – API Selection, Required, Optional, User Defined, MIDlets, Push Registry and Permissions.

  1. API SelectionThis is where you choose which version of MIDP your application will use and which optional packages (JSRs) are included. The default is set to JTWI (Java Technology for the Wireless Industry) which allows you to use MIDP 2.0 as well as MMAPI and other exciting things. If you’re having any problems with your application on your device try changing this to MIDP 1.0.
  2. RequiredThis tab includes various options which are essential for packaging a MIDlet suite. The MIDlet-Jar-URL attribute is where we will define the location of the packaged JAR file to be downloaded to the device.
  3. OptionalThis tab includes optional parameters for your MIDlet – such as the path to the icon for the entire suite, a description and a MIDlet-Info-URL parameter.
  4. User DefinedThis tab includes user defined variables that your MIDlet can use – such as a common URL that you don’t want to hard wire into the source code.
  5. MIDletsThis tab manages all the settings for the MIDlets within your suite. At the very least you need to have one file here. This is also where you set the path to the MIDlet’s icon resource.
  6. Push RegistryThis lets you configure the Push Registry which allows your MIDlet to listen and act on information received from a remote source. MIDP 2.0 Only.
  7. PermissionsUnder MIDP 1.0, applications could only access libraries packaged inside the suite – this was called the sandbox model. MIDP 2.0 introduces the concept of trusted applications which allow access beyond the sandbox. This section allows you to specify which APIs are accessible.

For our purposes – the most important property is the MIDlet-Jar-URL within the Required tab. Here are the steps you need to take:

  1. Create a folder on your web serverHopefully you have an account with a web provider – login to that account and create a directory for your MIDlets to live and be served from. I created the directory http://uberthings.com/mobile/midlets. Once you’ve got that, you need to make a few changes to allow your server (assumed to be Apache) to serve JAD and JAR files correctly. Go to the root of your account and edit or create your .htaccess file. Add these lines:AddType text/vnd.sun.j2me.app-descriptor jad
    AddType application/java-archive jar

    Save this file. If you’re not using Apache, ensure that your MIME types include the above two settings.

  2. Specify the MIDlet-Jar-URLClick on Settings then go to the Required Tab. In the MIDlet-Jar-URL field, fill in the absolute URL of your JAR file. This will normally be something like http://mydomain/mydir/HelloProject.jar. For my server, this was http://www.uberthings.com/mobile/midlets/HelloProject.jar.
  3. Package your MIDletClick on Project->Package->Create Package. This will create a .jar and a .jad file in your applications bin folder. For my application – this was c:\j2mewtk\apps\HelloProject\bin\HelloProject.jar and c:\j2mewtk\apps\HelloProject\bin\HelloProject.jad.
  4. Upload the packaged MIDlet suiteUpload the JAR and JAD files that the packaging operation created to the folder you created earlier.
  5. Test with your deviceOpen the WAP browser on your phone and point it to the URL of the JAD file. Using my example, this would be http://uberthings.com/mobile/midlets/HelloProject.jad. Your device should then prompt you to download and install the MIDlet. Carry it around and show it off to all your friends!

2. Cable / Bluetooth

If you’ve got a Bluetooth adaptor or a USB cable which connects directly to your phone, you can use this to quickly test your packaged midlet.

Windows XP/2000: Browse to the bin folder of your project, right click on the .jar file and select Send To->Bluetooth->YOURDEVICE.
MacOS X: Click on the Bluetooth icon in the menu bar, choose Send File. Send it to your device.
This should send a message to your phone which will install the MIDlet once opened. This should work on most Nokia Series 60 phones (3650, 6600, N-Gage etc).


Using Clob values at dynamic SQL

July 10, 2009

Today, i had a problem while trying to use a clob value at my dynamic sql. Let me explain the problem further;

Development IDE : Oracle Forms

Failed Function: forms_ddl

I was trying to give forms_ddl function a clob value which includes ‘insert into …_table (…) values(…)’ format insert sql. Everything was working fine. But then i had to insert a clob value that is more than 4000 character(As you know the biggest varchar2 value can be 4000 characters), then it failed to insert. I had a lot of research about this and i found out the problem lying behind it. It was the character limit. Forms_ddl function only takes 4000 character of sql and truncates if it comes more than 4000. 

So, after researching i found out a usage which i will share with you. Please take a careful look at the code section below.

declare

   c3 integer;

   c3_tmp integer;

   str varchar2(4000);

   tmp clob;– the value to be inserted

begin 

  c3 := dbms_sql.open_cursor;– opens a cursor for us to execute our sql command
  
  
  dbms_sql.parse(c3, str, 1);– this statement parses our sql. str is the parameter which our sql statements included.   

    –Other parameters can be used same.
 

  dbms_sql.bind_variable(c3, ‘:values’, tmp);–binding variable :values into our dynamic sql and telling Oracle  ———–that :values := tmp. By the help of this statement we do not have to write all the clob value into our dynamic sql. So —no character limit will effect this statement.

  c3_tmp := dbms_sql.execute(c3);– This statement executes our sql. Everything works fine.

  commit;

end;

 

–str is the string which is like ‘insert into … (column_names) values(values–but one of them is a clob value which is declared like a bind variable :values)’

example;

str := ‘insert into users_table (op_id,PlacesVisited) values (‘EOZER’,:values)’

this sql statement script can be used to insert user_table a clob value with bind variable.


Oracle Date Time Functions

June 29, 2009

SYSDATE

Sysdate represents current date and time in Oracle. 

Example;

select sysdate from dual

Result;

29/06/2009 1:41:10 PM

 

ADD_MONTHS

This function adds specified amount of months to date given. Its usage and results are like this;

declare

  x date;

begin

           x  :=  ’25/10/2009′;

           x := add_months(x,1);

           dbms_output.putline(x);

end;

Result;

25/11/2009

 

MONTHS_BETWEEN

This function is used to get the months between two date values given. The only detail with this function is that this function returns a float value. Because of this reason you can either use this value directly, truncate it, floor it, ceil it or round it. It is up to your usage.

Example;

select months_between(‘25/10/2009′,’26/12/2009′) from dual

Result;

-1.03225806451613

This value tells us that first date is past according to second date and more than one months are between these dates.

 

Date Format

To change the date format of our session we can use this Oracle DB command;

ALTER SESSION SET NLS_DATE_FORMAT = ‘DD/mm/YYYY HH24:MI:SS’;

This code changes our date time format to example given;

Result

25/10/2009 15:12:42

Date Formats Ex

There are so many date formats at Oracle that can be used. If you ask why we need this formats it is clear for me to say that you will absolutely need this formats in order to show your values correctly to en user.

You could want to show current date like this; ‘25/10/2009′ or like this ‘25-10-2009′ or just with numbers ‘25102009′. Every companies has their own styles of coding. Date formats are one of them. One company could tell you that they want you to show every dates at dd/mm/yyyy format.  If you do not format your dates each time you parse it to this format it can work fine at first. But, whenever someone tries to change machine’s NLS settings to another values then you are having problem. To avoid this kind of situations you should be using date formats for following situations;

        – When you are parsing date value to a string value (varchar…);

                 * You can use to_char(date,’format’)–date and format are in varchar format.

                 example;

                 select to_char(sysdate,’dd/mm,yyyy’) from dual;

                 Retuns

                  29/06,2009

                 Example 2

                 select to_char(sysdate,’day-mon-year’) from dual

                 Retuns

                 mon-june-two thousand nine

                

                   You can convert your date values at any format you want. As in the second example you can convert date values to human language format.  It takes this formats from NLS(Language) settings.

 

           – When you want to convert char to date;

                    * You can use to_date function

                     Example

                     declare

                           x date;

                     begin

                             x := to_date(‘25/10/2009′,’dd/mm/yyy’) ;

                     end;

                     Warning: Although Oracle recognises your computer’s date format automatically to keep your software portable you should specify format parameter each time you use it.

NEXT_DAY

This function returns the first date that the day of week specified comes.

Example;

SELECT NEXT_DAY(‘27/06/2009′, ‘MON’) FROM dual;

Returns

29/06/2009

 

ROUND

 
This function round the date value given. It uses the standard rounding rules. Rounds to nearest date.

Example

SELECT ROUND(TO_DATE(‘27-11-01′),‘mm’) NEW_YEAR from dual

 

Returns

01/12/0001


Debugging on pl/sql developer

June 22, 2009

Hello,

This is my first post on wordpress. I want to tell you about how to do debugging stuff on pl/sql developer at Oracle database.

Firstly, a database is needed to be connected. To do this, we have to add tns file at our C:\DevSuite10g\NETWORK\ADMIN\tnsnames.ora location. After making sure the tns file is correctly placed there, we can start working on pl/sql developer.

Open pl/sql developer program, select the database to connect, write your user id and password then click connect.

congratulations! You have successfully connected to database. You have two ways to open debug window. But i will tell you one. Click on the new button(with sheet picture at bottom of page), it shows a menu then select test window. Write down your code there then click start debuggin button. Program will work line by line. then you can implement your classical style debugging there.

The main diffrence between debugging on normal programming languages and pl/sql is that, at pl/sql you have to make sure what all the select statements returns. Because of this reason while debugging, get all the sql statement’s and its subqueries’ return values and calculate them correctly.

Don’t forget, the biggest mistakes at pl/sql programs are made by mistaken select statements.