Partition pruning, Nested loops

Hi,
I am having a problem with getting partition pruning in a query. I've managed to dumb down the problem to two tables and a minimal query (see below).
Basically, I have a partitioned table "Yearly Facts", and a helper table "Current Year" that always contain 1 row. The sole purpose of this one row is to tell what the curent year is, what the previous year was and what the next year will be. (In the real problem, there are non-standard timeperiods, so one cannot just calculate previous and next by adding/subtracting 1 as would be possible in this example).
The following query is executed the way I want.
It performs a scan on current_year, and then nested loop into the facts. And partition pruning was happening.
select sum(decode(a.year_key, b.curr_year, some_measure)) as curr_year_measure
  from yearly_fact_t a
      ,current_year  b
where a.year_key = b.curr_year;
| Id  | Operation                  | Name          | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
|   0 | SELECT STATEMENT           |               |     1 |    39 |     4   (0)| 00:00:01 |       |    |
|   1 |  SORT AGGREGATE            |               |     1 |    39 |            |          |       |    |
|   2 |   NESTED LOOPS             |               |     1 |    39 |     4   (0)| 00:00:01 |       |    |
|   3 |    INDEX FAST FULL SCAN    | SYS_C00247890 |     1 |    13 |     2   (0)| 00:00:01 |       |    |
|   4 |    PARTITION RANGE ITERATOR|               |     1 |    26 |     2   (0)| 00:00:01 |   KEY |   KEY |
|*  5 |     TABLE ACCESS FULL      | YEARLY_FACT_T |     1 |    26 |     2   (0)| 00:00:01 |   KEY |   KEY |
Predicate Information (identified by operation id):
   5 - filter("A"."YEAR_KEY"="B"."CURR_YEAR")The following query is where I have my problem.
The basic xplan is the same, but for some reason the cbo gave up and decide to scan all partitions, which was not very scalable on production data :)
I would have thought that the plan would be the same.
select sum(decode(a.year_key, b.curr_year, some_measure)) as curr_year_measure
      ,sum(decode(a.year_key, b.prev_year, some_measure)) as prev_year_measure
  from yearly_fact_t a
      ,current_year  b
where a.year_key = b.curr_year
    or a.year_key = b.prev_year;
| Id  | Operation             | Name          | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
|   0 | SELECT STATEMENT      |               |     1 |    52 |    13   (0)| 00:00:01 |       |       |
|   1 |  SORT AGGREGATE       |               |     1 |    52 |            |          |       |       |
|   2 |   NESTED LOOPS        |               |     4 |   208 |    13   (0)| 00:00:01 |       |       |
|   3 |    TABLE ACCESS FULL  | CURRENT_YEAR  |     1 |    26 |     4   (0)| 00:00:01 |       |       |
|   4 |    PARTITION RANGE ALL|               |     4 |   104 |     9   (0)| 00:00:01 |     1 |     6 |
|*  5 |     TABLE ACCESS FULL | YEARLY_FACT_T |     4 |   104 |     9   (0)| 00:00:01 |     1 |     6 |
Predicate Information (identified by operation id):
   5 - filter("A"."YEAR_KEY"="B"."CURR_YEAR" OR "A"."YEAR_KEY"="B"."PREV_YEAR")
-- drop table yearly_fact_t purge;
-- drop table current_year  purge;
create table current_year(
   curr_year number(4) not null
  ,prev_year number(4) not null
  ,next_year number(4) not null
  ,primary key(curr_year)
  ,unique(prev_year)
  ,unique(next_year)
insert into current_year(curr_year, prev_year, next_year) values(2010, 2009, 2011);
commit;
create table yearly_fact_t(
   year_key     number(4) not null
  ,some_dim_key number    not null
  ,some_measure number    not null
partition by range(year_key)(
   partition p2007 values less than(2008)
  ,partition p2008 values less than(2009)
  ,partition p2009 values less than(2010)
  ,partition p2010 values less than(2011)
  ,partition p2011 values less than(2012) 
  ,partition pmax  values less than(maxvalue)
insert into yearly_fact_t(year_key, some_dim_key, some_measure) values(2007,1, 10);
insert into yearly_fact_t(year_key, some_dim_key, some_measure) values(2008,1, 20);
insert into yearly_fact_t(year_key, some_dim_key, some_measure) values(2009,1, 30);
insert into yearly_fact_t(year_key, some_dim_key, some_measure) values(2010,1, 40);
commit; What can I do to get partition pruning to happen in the second query?
Or even better, what is it in my query that prevents it from happening?
We're running Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit.
Best regards
Ronnie

Hi Ronnie,
Check whether your statistics are up to date.
SQL> set autotrace traceonly exp
SQL> select sum(decode(a.year_key, b.curr_year, some_measure)) as curr_year_measure
  2        ,sum(decode(a.year_key, b.prev_year, some_measure)) as prev_year_measure
  3    from yearly_fact_t a
  4        ,current_year  b
  5   where a.year_key = b.curr_year
  6      or a.year_key = b.prev_year;
Execution Plan
Plan hash value: 229094315
| Id  | Operation             | Name          | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
|   0 | SELECT STATEMENT      |               |     1 |    52 |    10   (0)| 00:00:01 |       |       |
|   1 |  SORT AGGREGATE       |               |     1 |    52 |            |          |       |       |
|   2 |   NESTED LOOPS        |               |     4 |   208 |    10   (0)| 00:00:01 |       |       |
|   3 |    TABLE ACCESS FULL  | CURRENT_YEAR  |     1 |    26 |     3   (0)| 00:00:01 |       |       |
|   4 |    PARTITION RANGE ALL|               |     4 |   104 |     7   (0)| 00:00:01 |     1 |     6 |
|*  5 |     TABLE ACCESS FULL | YEARLY_FACT_T |     4 |   104 |     7   (0)| 00:00:01 |     1 |     6 |
Predicate Information (identified by operation id):
   5 - filter("A"."YEAR_KEY"="B"."CURR_YEAR" OR "A"."YEAR_KEY"="B"."PREV_YEAR")
Note
   - dynamic sampling used for this statement
SQL> set autotrace off
SQL> exec dbms_stats.gather_table_stats(user, 'current_year', estimate_percent=>100, cascade=>true, method_opt
=>'for all columns size 1');
PL/SQL procedure successfully completed.
SQL>
SQL> exec dbms_stats.gather_table_stats(user, 'yearly_fact_t', estimate_percent=>100, cascade=>true, method_op
t=>'for all columns size 1');
PL/SQL procedure successfully completed.
SQL> set autotrace traceonly exp
SQL> select sum(decode(a.year_key, b.curr_year, some_measure)) as curr_year_measure
  2        ,sum(decode(a.year_key, b.prev_year, some_measure)) as prev_year_measure
  3    from yearly_fact_t a
  4        ,current_year  b
  5   where a.year_key = b.curr_year
  6      or a.year_key = b.prev_year;
Execution Plan
Plan hash value: 2253546831
| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
|   0 | SELECT STATEMENT            |               |     1 |    15 |     8   (0)| 00:00:01 |       |       |
|   1 |  SORT AGGREGATE             |               |     1 |    15 |            |          |       |       |
|   2 |   CONCATENATION             |               |       |       |            |          |       |       |
|   3 |    NESTED LOOPS             |               |     1 |    15 |     4   (0)| 00:00:01 |       |       |
|   4 |     TABLE ACCESS FULL       | CURRENT_YEAR  |     1 |     8 |     3   (0)| 00:00:01 |       |       |
|   5 |     PARTITION RANGE ITERATOR|               |     1 |     7 |     1   (0)| 00:00:01 |   KEY |   KEY |
|*  6 |      TABLE ACCESS FULL      | YEARLY_FACT_T |     1 |     7 |     1   (0)| 00:00:01 |   KEY |   KEY |
|   7 |    NESTED LOOPS             |               |     1 |    15 |     4   (0)| 00:00:01 |       |       |
|   8 |     TABLE ACCESS FULL       | CURRENT_YEAR  |     1 |     8 |     3   (0)| 00:00:01 |       |       |
|   9 |     PARTITION RANGE ITERATOR|               |     1 |     7 |     1   (0)| 00:00:01 |   KEY |   KEY |
|* 10 |      TABLE ACCESS FULL      | YEARLY_FACT_T |     1 |     7 |     1   (0)| 00:00:01 |   KEY |   KEY |
Predicate Information (identified by operation id):
   6 - filter("A"."YEAR_KEY"="B"."PREV_YEAR")
  10 - filter("A"."YEAR_KEY"="B"."CURR_YEAR" AND LNNVL("A"."YEAR_KEY"="B"."PREV_YEAR"))
SQL> set autotrace off
SQL>Asif Momen
http://momendba.blogspot.com

Similar Messages

  • Reference partitioning and partition pruning

    Hi All,
    I am on v 11.2.0.3.
    I have a pair of typical parent-child tables. Child table is growing like hell, hence we want to partition it, which will be used for deleting/dropping old data later on.
    There is no partitioning key in the child table which I can use for relating the data to the time when data was created. So, I thought I can use the timestamp from parent table for partitioning the parent table and reference partition the child table.
    I am more concerned about the child table (or the queries running on the child table) in terms of performance. ITEM_LIST_ID from the child table is extensively used in queries to access data from child table.
    How will partition pruning work when the child table is queried on the foreign key? will it every time go to the parent table, find out the partition and then resolve the partition for child table?
    The setup is given in the scripts below, will it cause lot of locking (to resolve partitions)? or am I worrying for nothing?
    Here are the scripts
    CREATE TABLE ITEM_LISTS /* Parent table, tens of thousands of records */
      ITEM_LIST_ID    NUMBER(10)     NOT NULL PRIMARY KEY, /* Global index on partitioned table !!! */
      LIST_NAME       VARCHAR2(500)  NOT NULL,
      FIRST_INSERTED  TIMESTAMP(6)   NOT NULL
    PARTITION BY RANGE ( FIRST_INSERTED )
      partition p0 values less than ( to_date('20130101','YYYYMMDD') ),
      partition p201301 values less than ( to_date('20130201','YYYYMMDD') ),
      partition p201302 values less than ( to_date('20130301','YYYYMMDD') ),
      partition p201303 values less than ( to_date('20130401','YYYYMMDD') ),
      partition p201304 values less than ( to_date('20130501','YYYYMMDD') ),
      partition p201305 values less than ( to_date('20130601','YYYYMMDD') )
    CREATE INDEX ITEM_LISTS_IDX1 ON ITEM_LISTS ( LIST_NAME ) LOCAL ;
    CREATE TABLE ITEM_LIST_DETAILS /* Child table, millions of records */
      ITEM_ID        NUMBER(10)     NOT NULL,
      ITEM_LIST_ID   NUMBER(10)     NOT NULL, /* Always used in WHERE clause by lots of big queries */
      CODE           VARCHAR2(30)   NOT NULL,
      ALT_CODE       VARCHAR2(30)   NOT NULL,
      CONSTRAINT   ITEM_LIST_DETAILS_FK
      FOREIGN KEY  ( ITEM_LIST_ID ) REFERENCES ITEM_LISTS
    PARTITION BY REFERENCE ( ITEM_LIST_DETAILS_FK )
    CREATE INDEX ITEM_LIST_DETAILS_IDX1 ON ITEM_LIST_DETAILS (ITEM_ID) LOCAL;
    CREATE INDEX ITEM_LIST_DETAILS_IDX2 ON ITEM_LIST_DETAILS (ITEM_LIST_ID, CODE) LOCAL;Any thoughts / opinions / corrections ?
    Thanks in advance

    To check how partition pruning works here, I inserted some data in these tables. Inserted data in ITEM_LISTS (parent) from DBA_OBJECTS ( object_id => item_list_id, object_name => list_name, first_inserted => manually created). Also created corresponding child data in ITEM_LIST_DETAILS, so that, for every item_list_id in parent about 5000 records go in child table.
    Looking at the queries and plan below, my question is, what exactly does the operations "PARTITION REFERENCE SINGLE" and "PARTITION REFERENCE ITERATOR" imply ??
    I gave a search on "PARTITION REFERENCE ITERATOR" in Oracle 11.2 documentation, it says "No exact match found" !!
    /* Direct query on child table */
    SQL> select count(*) from item_list_details where item_list_id = 6323 ;
      COUNT(*)
          5000
    1 row selected.
    Execution Plan
    Plan hash value: 2798904155
    | Id  | Operation                   | Name                   | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
    |   0 | SELECT STATEMENT            |                        |     1 |     5 |    22   (0)| 00:00:01 |       |       |
    |   1 |  SORT AGGREGATE             |                        |     1 |     5 |            |          |       |       |
    |   2 |   PARTITION REFERENCE SINGLE|                        |  5000 | 25000 |    22   (0)| 00:00:01 |   KEY |   KEY |
    |*  3 |    INDEX RANGE SCAN         | ITEM_LIST_DETAILS_IDX2 |  5000 | 25000 |    22   (0)| 00:00:01 |   KEY |   KEY |
    Predicate Information (identified by operation id):
       3 - access("ITEM_LIST_ID"=6323)
    SQL> select * from temp1; /* Dummy table to try out some joins */
    OBJECT_ID OBJECT_NAME
          6598 WRH$_INTERCONNECT_PINGS
    1 row selected.
    /* Query on child table, joining with some other table */
    SQL> select count(*)
      2  from temp1 d, ITEM_LIST_DETAILS i1
      3  where d.object_id = i1.item_list_id
      4  and d.object_name = 'WRH$_INTERCONNECT_PINGS';
      COUNT(*)
          5000
    1 row selected.
    Execution Plan
    Plan hash value: 2288153583
    | Id  | Operation                      | Name                   | Rows  | Bytes | Cost (%CPU)| Time  | Pstart| Pstop |
    |   0 | SELECT STATEMENT               |                        |     1 |    70 |    24   (0)| 00:00:01 |       |       |
    |   1 |  SORT AGGREGATE                |                        |     1 |    70 |            |       |  |       |
    |   2 |   NESTED LOOPS                 |                        |  5000 |   341K|    24   (0)| 00:00:01 |       |       |
    |*  3 |    TABLE ACCESS FULL           | TEMP1                  |     1 |    65 |     3   (0)| 00:00:01 |       |       |
    |   4 |    PARTITION REFERENCE ITERATOR|                        |  5000 | 25000 |    21   (0)| 00:00:01 |   KEY |   KEY |
    |*  5 |     INDEX RANGE SCAN           | ITEM_LIST_DETAILS_IDX2 |  5000 | 25000 |    21   (0)| 00:00:01 |   KEY |   KEY |
    Predicate Information (identified by operation id):
       3 - filter("D"."OBJECT_NAME"='WRH$_INTERCONNECT_PINGS')
       5 - access("D"."OBJECT_ID"="I1"."ITEM_LIST_ID")

  • Partition Pruning Aint Happening

    I have a situation where Oracle pruning is not happening and this situation is getting worse when the search criteria is close to current date.
    Table has a date based partition. SQL Statement has 2 partitioned tables. Date range is applied on a relatively smaller daily partitioned table and further joined to the next table (Its also date based partition). First table has partition column in the where clause and it joins to the next table using the partitioned column.
    SQL does partition pruning even for a month range search if the date range is in August. It will do partition pruning only for 25 days for september where clause. Likewise the where clause date range ability for partition pruning goes down and It will only do partition pruning for where clause with 5 days. If the where clause has more than 6 days (Mar 01 Thru Mar 06) in March 2009, Oracle does All partitions.
    Query is examined and it contains partition column in the where clause and we have also gathered 100% statistics of the table which is not partition pruning. Data growth is happening relatively each month.
    Sample: -
    Select 1
    From TAB1, TAB2
    Where TAB1.SELECT_DATE >= '01JAN2009
    And TAB1.SELECT_DATE <= '31JAN2009
    And TAB2.DATE_SELECT = TAB1.DATE_SELECT
    TAB1 Is a daily partition with SELECT_DATE column. Oracle is able to successfully do partition pruning on this table. But TAB2 partition pruning is not happening.
    How I can overcome this situation? Thanks for your help.
    Here is the explain plan for the SQL statement

    | Id  | Operation                            | Name         | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
    |   0 | SELECT STATEMENT                     |              |  1224 | 96696 |       |   978K  (4)| 01:21:35 |       |       |
    |   1 |  HASH GROUP BY                       |              |  1224 | 96696 |       |   978K  (4)| 01:21:35 |       |       |
    |*  2 |   HASH JOIN                          |              |  1122K|    84M|    49M|   978K  (4)| 01:21:34 |       |       |
    |*  3 |    HASH JOIN                         |              |  1122K|    36M|       |  5218   (4)| 00:00:27 |       |       |
    |   4 |     COLLECTION ITERATOR PICKLER FETCH| TABLE FUNC   |       |       |       |            |          |       |       |
    |   5 |     PARTITION RANGE ITERATOR         |              |   729K|    22M|       |  5145   (3)| 00:00:26 |   413 |   422 |
    |   6 |      PARTITION LIST ALL              |              |   729K|    22M|       |  5145   (3)| 00:00:26 |     1 |     2 |
    |*  7 |       MAT_VIEW ACCESS FULL           | TAB_01       |   729K|    22M|       |  5145   (3)| 00:00:26 |   825 |   844 |
    |   8 |    PARTITION RANGE ALL               |              |    84M|  3623M|       |   575K  (5)| 00:47:59 |     1 |   970 |
    |   9 |     TABLE ACCESS FULL                | TAB_02       |    84M|  3623M|       |   575K  (5)| 00:47:59 |     1 |   970 |
    Predicate Information (identified by operation id):
       2 - access("TAB_02"."SELECT_DATE"="TAB_01"."SELECT_DATE" AND "TAB_02"."SELECT_NUMBER"="TAB_01"."SELECT_NUMBER")
       3 - access("TAB_01"."TAG_ID"=SYS_OP_ATG(VALUE(KOKBF$),16,17,2))
       7 - filter("TAB_01"."SELECT_DATE"<=TO_DATE('2009-02-10 00:00:00', 'yyyy-mm-dd hh24:mi:ss'))Following is the explain paln where partition elimination happening for a shorter date range search
    | Id  | Operation                            | Name         | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
    |   0 | SELECT STATEMENT                     |              |   714 | 56406 |   851K  (1)| 01:10:56 |       |       |
    |   1 |  HASH GROUP BY                       |              |   714 | 56406 |   851K  (1)| 01:10:56 |       |       |
    |   2 |   NESTED LOOPS                       |              |   621K|    46M|   850K  (1)| 01:10:55 |       |       |
    |*  3 |    HASH JOIN                         |              |   621K|    20M|  3210   (3)| 00:00:17 |       |       |
    |   4 |     COLLECTION ITERATOR PICKLER FETCH| TABLE FUNC   |       |       |            |          |       |       |
    |   5 |     PARTITION RANGE ITERATOR         |              |   403K|    12M|  3152   (3)| 00:00:16 |   413 |   418 |
    |   6 |      PARTITION LIST ALL              |              |   403K|    12M|  3152   (3)| 00:00:16 |     1 |     2 |
    |*  7 |       MAT_VIEW ACCESS FULL           | TAB_01       |   403K|    12M|  3152   (3)| 00:00:16 |   825 |   836 |
    |   8 |    PARTITION RANGE ITERATOR          |              |     1 |    45 |     2   (0)| 00:00:01 |   KEY |   KEY |
    |   9 |     TABLE ACCESS BY LOCAL INDEX ROWID| TAB_02       |     1 |    45 |     2   (0)| 00:00:01 |   KEY |   KEY |
    |* 10 |      INDEX RANGE SCAN                | TAB_02_PK    |     1 |       |     1   (0)| 00:00:01 |   KEY |   KEY |
    Predicate Information (identified by operation id):
       3 - access("TAB_01"."TAG_ID"=SYS_OP_ATG(VALUE(KOKBF$),16,17,2))
       7 - filter("TAB_01"."SELECT_DATE"<=TO_DATE('2009-02-06 00:00:00', 'yyyy-mm-dd hh24:mi:ss'))
      10 - access("TAB_02"."SELECT_DATE"="TAB_01"."SELECT_DATE" AND "TAB_02"."SELECT_NUMBER"="TAB_01"."SELECT_NUMBER")Query where partition elimination not happening on the second table is having date range of 7 days or more. SO the first explain plan is for Feb-01 Thru Feb 10 search
    Query where partition elimination happening on the second table is having date range of 7 days or less. The second explain plan is for Feb-01 Thru Feb-06 search
    This is great.
    Edited by: user10929035 on Mar 24, 2009 8:18 AM                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           

  • Partition Pruning on Interval Range Partitioned Table not happening when SYSDATE used in Where Clause

    We have tables that are interval range partitioned on a DATE column, with a partition for each day - all very standard and straight out of Oracle doc.
    A 3rd party application queries the tables to find number of rows based on date range that is on the column used for the partition key.
    This application uses date range specified relative to current date - i.e. for last two days would be "..startdate > SYSDATE -2 " - but partition pruning does not take place and the explain plan shows that every partition is included.
    By presenting the query using the date in a variable partition pruning does table place, and query obviously performs much better.
    DB is 11.2.0.3 on RHEL6, and default parameters set - i.e. nothing changed that would influence optimizer behavior to something unusual.
    I can't work out why this would be so. It very easy to reproduce with simple test case below.
    I'd be very interested to hear any thoughts on why it is this way and whether anything can be done to permit the partition pruning to work with a query including SYSDATE as it would be difficult to get the application code changed.
    Furthermore to make a case to change the code I would need an explanation of why querying using SYSDATE is not good practice, and I don't know of any such information.
    1) Create simple partitioned table
    CREATETABLE part_test
       (id                      NUMBER NOT NULL,
        starttime               DATE NOT NULL,
        CONSTRAINT pk_part_test PRIMARY KEY (id))
    PARTITION BY RANGE (starttime) INTERVAL (NUMTODSINTERVAL(1,'day')) (PARTITION p0 VALUES LESS THAN (TO_DATE('01-01-2013','DD-MM-YYYY')));
    2) Populate table 1million rows spread between 10 partitions
    BEGIN
        FOR i IN 1..1000000
        LOOP
            INSERT INTO part_test (id, starttime) VALUES (i, SYSDATE - DBMS_RANDOM.value(low => 1, high => 10));
        END LOOP;
    END;
    EXEC dbms_stats.gather_table_stats('SUPER_CONF','PART_TEST');
    3) Query the Table for data from last 2 days using SYSDATE in clause
    EXPLAIN PLAN FOR
    SELECT  count(*)
    FROM    part_test
    WHERE   starttime >= SYSDATE - 2;
    | Id  | Operation                 | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
    |   0 | SELECT STATEMENT          |           |     1 |     8 |  7895  (1)| 00:00:01 |       |       |
    |   1 |  SORT AGGREGATE           |           |     1 |     8 |            |          |       |       |
    |   2 |   PARTITION RANGE ITERATOR|           |   111K|   867K|  7895   (1)| 00:00:01 |   KEY |1048575|
    |*  3 |    TABLE ACCESS FULL      | PART_TEST |   111K|   867K|  7895   (1)| 00:00:01 |   KEY |1048575|
    Predicate Information (identified by operation id):
       3 - filter("STARTTIME">=SYSDATE@!-2)
    4) Now do the same query but with SYSDATE - 2 presented as a literal value.
    This query returns the same answer but very different cost.
    EXPLAIN PLAN FOR
    SELECT count(*)
    FROM part_test
    WHERE starttime >= (to_date('23122013:0950','DDMMYYYY:HH24MI'))-2;
    | Id  | Operation                 | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
    |   0 | SELECT STATEMENT          |           |     1 |     8 |   131  (0)| 00:00:01 |       |       |
    |   1 |  SORT AGGREGATE           |           |     1 |     8 |            |          |       |       |
    |   2 |   PARTITION RANGE ITERATOR|           |   111K|   867K|   131   (0)| 00:00:01 |   356 |1048575|
    |*  3 |    TABLE ACCESS FULL      | PART_TEST |   111K|   867K|   131   (0)| 00:00:01 |   356 |1048575|
    Predicate Information (identified by operation id):
       3 - filter("STARTTIME">=TO_DATE(' 2013-12-21 09:50:00', 'syyyy-mm-dd hh24:mi:ss'))
    thanks in anticipation
    Jim

    As Jonathan has already pointed out there are situations where the CBO knows that partition pruning will occur but is unable to identify those partitions at parse time. The CBO will then use a dynamic pruning which means determine the partitions to eliminate dynamically at run time. This is why you see the KEY information instead of a known partition number. This is to occur mainly when you compare a function to your partition key i.e. where partition_key = function. And SYSDATE is a function. For the other bizarre PSTOP number (1048575) see this blog
    http://hourim.wordpress.com/2013/11/08/interval-partitioning-and-pstop-in-execution-plan/
    Best regards
    Mohamed Houri

  • Partition Pruning - Dimension and FACT tables..

    Hi
    I have a DWH environment where we have partitioned the FACT table by a date column. This is RANGE partition. The TIME dimension table joins to the FACT table based on this date. However the end user queries will typically be fired using a different column in the time dimension that will hold more VIEWABLE date values (e.g.) in format MON-YYYY or YYYY-MM etc..
    The query is autogenerated by the viewer tool. The SQL has something like
    select sum(balance), MONTH from fact a, dim_time b
    where a.date = b.date and <-- this the partitioned key in fact
    b.month_year_col = 'Apr-2006' <-- Dimension filter.
    In the above case, Oracle is not doing PARTITION PRUNING. I have 24 period data and in the explain plan i can see it goes to the entire 24 periods. However if i change the query to
    select sum(balance), MONTH from fact a, dim_time b
    where a.date = b.date and <-- this the partitioned key in fact
    b.date = '31-Apr-2006' <-- Dimension filter.
    it does partition pruning. The explain plan shows that i goes to only one partition.
    Any help on this please. I would need the first query to use PARTITION PRUNING.
    Thanks
    bala

    Hi All
    Got it to work with these 3 parameters
    alter system set "_subquery_pruning_enabled" = true
    alter session set "_subquery_pruning_cost_factor"=1;
    alter session set "_subquery_pruning_reduction"=100;
    Thanks for all those who had a look into my question.
    Regards
    bala

  • Building Tree hierarchy Using nested loops and class cl_gui_column_tree

    Hello gurus,
    I want to create a tree report using custom container and class cl_gui_column_tree. I have read and understood the standard demo report which SAP has provided i.e. SAPCOLUMN_TREE_CONTROL_DEMO. But in this report all the levels nodes are created as constants and hardcoded. I want to create hierarchy using nested loops. For this i took one example of a hierarchy of VBAK-VBELN->VBAP-POSNR Like One sales order has many line items and each line item can have number of line items in billing plan.
    I have done some coding for it.
    FORM build_tree USING node_table TYPE treev_ntab
                                           item_table TYPE zitem_table.              " i created the zitem_table table type of mtreeitm in SE11.
      DATA: node TYPE treev_node,
                 item TYPE mtreeitm.
      node-node_key = root.
      CLEAR node-relatkey.
      CLEAR node-relatship.
      node-hidden = ' '.
      node-disabled = ' '.
      CLEAR node-n_image.
      CLEAR node-exp_image.
      node-isfolder = 'X'.
      node-expander = 'X'.
      APPEND node TO node_table.
      item-node_key = root.
      item-item_name = colm1.
      item-class = cl_gui_column_tree=>item_class_text.
      item-text = 'Root'.
      APPEND item TO item_table.
      item-node_key = root.
      item-item_name = colm2.
      item-class = cl_gui_column_tree=>item_class_text.
      item-text = 'Amount'.
      APPEND item TO item_table.
      LOOP AT it_vbeln INTO wa_vbeln.
        node-node_key = wa_vbeln-vbeln.
        node-relatkey = root.
        node-relatship = cl_gui_column_tree=>relat_last_child.
        node-hidden = ' '.
        node-disabled = ' '.
        CLEAR node-n_image.
        CLEAR node-exp_image.
        node-isfolder = 'X'.
        node-expander = 'X'.
        APPEND node TO node_table.
        item-node_key = wa_vbeln-vbeln.
        item-item_name = colm1.
        item-class = cl_gui_column_tree=>item_class_text.
        item-text = wa_vbeln-vbeln.
        APPEND item TO item_table.
        item-node_key = wa_vbeln-vbeln.
        item-item_name = colm2.
        item-class = cl_gui_column_tree=>item_class_text.
        item-text = wa_vbeln-netwr.
        APPEND item TO item_table.
        LOOP AT it_posnr INTO wa_posnr.
        node-node_key = wa_posnr-posnr.
        node-relatkey = wa_vbeln-vbeln.
        node-relatship = cl_gui_column_tree=>relat_last_child.
        node-hidden = ' '.
        node-disabled = ' '.
        CLEAR node-n_image.
        CLEAR node-exp_image.
        node-isfolder = ' '.
        node-expander = ' '.
        APPEND node TO node_table.
        item-node_key = wa_posnr-posnr.
        item-item_name = colm1.
        item-class = cl_gui_column_tree=>item_class_text.
        item-text = wa_posnr-posnr.
        APPEND item TO item_table.
        item-node_key = wa_posnr-posnr.
        item-item_name = colm2.
        item-class = cl_gui_column_tree=>item_class_text.
        item-text = wa_posnr-netpr.
        APPEND item TO item_table.
        ENDLOOP.
      ENDLOOP.
    ENDFORM.
    Now this program compiles fine and runs till there is only one level. That is root->vbeln. But when i add one more loop of it_posnr it gives me runtime error of message type 'X'. The problem i found was uniqueness of item-item_name as all the sales order have posnr = 0010. What could be done? I tried giving item_name unique hierarchy level using counters just like stufe field in prps eg. 10.10.10, 10.10.20,10.20.10,10.20.20,20.10.10 etc.. etc.. but still i am getting runtime error when i add one more hierarchy using nested loop. Plz guide.
    Edited by: Yayati6260 on Jul 14, 2011 7:25 AM

    Hello all,
    Thanks the issue is solved. The node key was not getting a unique identification as nodekey. I resolved the issue by generating unique identification for each level. Thanks all,
    Regards
    Yayati Ekbote

  • Problem with Nested loop in Fox-Formula

    Dear Experts,
    Let s share the scenario :
    MaterialGroups with following Keys for Example AAAA, BBBB, CCCC..., Materialgroups are selected in the 1st input ready query, which is assigned to DataProvider DP_1 in a  webtemplate.
    every Materialgroup has several Materials, for instance:
    Materialgroup AAAA has following Materials: AAAA10, AAAA11, AAAA12, AAAA13...
    Materials are  selected in a second  input ready Query, which is assigned to a second DataProvider DP_2 in the Same Webtemplate as the query 1.
    Both Materialgroup and Material are based on the same Aggreagtion level and same real time cube.
    I want to copy the input values for every  MaterialGroup ( 1st query, DP_1) only to it s own Materials (2cond Query, DP_2).
    To resolve this Issue i wrote the following Fox Formula code with a nested loop, however it does not work properly. when I m debugging the code, i could release that the second Loop was ignored.but wehn i replace the second loop (nested loop) with a fixed value it s seems to work properly
    DATA MG1 TYPE MATG.<------ MaterialGroup
    DATA MT1 TYPE MAT.<----
    Material
    DATA S1 TYPE STRING.
    DATA S2 TYPE STRING.
    DATA S3 TYPE STRING
    DATA K TYPE F.
    DATA Z TYPE F.
    FOREACH MG1.
    To check Materialgroup in debugger
    S1= MG1.
    BREAK-POINT.
    K = {KEYfIG, #, MG1}.
    BREAK-POINT.
    FOREACH  MT1.   <----- if i set MT1 to a fixed value like AAAA11 then S3 get the wished value namely AAAA
    S2 = MT1.
    BREAK-POINT.
    S3 =  SUBSTR (MT1, 0, 4).  
    BREAK-POINT.
    IF S1 = S3.
    {KEYFIG, MT1, #} = K.
    following Statement is only used To check in debugger if Material has become the same Materialgroup value
    Z = {KEYFIG, MT1, #}.
    BREAK-POINT.
    ENDIF.
    ENDFOR.
    ENDFOR.
    Thakns for any help
    Frank
    Edited by: FRYYYBM on Mar 17, 2011 10:54 PM
    Edited by: FRYYYBM on Mar 17, 2011 11:06 PM

    Hi,
    Please try this way.
    DATA MG1 TYPE MATG.<------ MaterialGroup
    DATA MT1 TYPE MAT.<----
    Material
    DATA S1 TYPE STRING.
    DATA S2 TYPE STRING.
    DATA S3 TYPE STRING
    DATA K TYPE F.
    DATA Z TYPE F.
    FOREACH MT1.
    FOREACH MG1.
    To check Materialgroup in debugger
    S1= MG1.
    BREAK-POINT.
    K = {KEYfIG, #, MG1}.
    BREAK-POINT.
    FOREACH MT1. <----- if i set MT1 to a fixed value like AAAA11 then S3 get the wished value namely AAAA
    S2 = MT1.
    BREAK-POINT.
    S3 = SUBSTR (MT1, 0, 4).
    BREAK-POINT.
    IF S1 = S3.
    {KEYFIG, MT1, #} = K.
    following Statement is only used To check in debugger if Material has become the same Materialgroup value
    Z = {KEYFIG, MT1, #}.
    BREAK-POINT.
    ENDIF.
    ENDFOR.
    ENDFOR.
    ENDFOR.
    Thanks.
    With regards,
    Anand Kumar

  • Creating nested loops

    Hi!
    I would like to list all Combinations of a list A and a list B (each containing 5 integers) in a third list C in order to get 25 combinations. I am intending to use nested loops so that on the first loop the second loop starts and then the result lets say list A + list B are listed in the list C. Is there any other way of doing this with Labview or I am on the right track?
    Best Regards,
    Hamid  

    You can use the polymorphic array math to accomplish this.  Inside of a single for loop, index Array A and add that to the entire Array B in one shot.  At this point, there are numerous ways to take the output.  Probably the simpliest is to reshape the output 2D array into a 1D array.  For better memory allocation, you can preinitialize a 1D array and replace elements in the for loop but in the end it accomplishes the same task.  See attached example (LV7.1.1).  Of course everything is dependant on what you are going to do with this, what operations, when and where the numbers come from.
    Paul
    Paul <--Always Learning!!!
    sense and simplicity.
    Browse my sample VIs?
    Attachments:
    arrayMath.vi ‏33 KB

  • XML nested Loop?

    hi all.
    I´ve just completed a little test for making a tree
    component with custom
    icons / bransch.
    However, i can only get my first branch to show custom
    icons.(links -
    document) I figure I need to make a nested loop to Iterate
    over
    nextSibling?. I tried ALOT, but i guess I´m doing
    something completely
    wrong.
    here is code for my tree so far:
    my_xml = new XML();
    my_xml.ignoreWhite = true;
    my_xml.load("tree.xml");
    my_xml.onLoad = function(){
    myTree.dataProvider = this.firstChild;
    var folders = my_xml.firstChild.firstChild;
    var docs = folders.childNodes;
    for (var i=0; i < docs.length; i++){
    currDoc = docs
    trace(docs);
    var docIcon = currDoc.attributes.pic;
    switch(docIcon){
    case "pdf":
    myTree.setIcon(currDoc, "pdfIcon");
    break;
    case "word":
    myTree.setIcon(currDoc, "wordIcon");
    break;
    case "excel":
    myTree.setIcon(currDoc, "excelIcon");
    break;
    case "ie":
    myTree.setIcon(currDoc, "ieIcon");
    break;
    }//switch
    } //for
    };//onLoad
    And here is the XML I used:
    <node label="» Dokument typer">
    <node label="» links - document">
    <node label="test.url" url="
    http://www." pic="ie" info="test text" />
    <node label="test.doc" url="test.doc" pic="word"
    info="test text" />
    <node label="test.excel" url="test.xls" pic="excel"
    info="test text" />
    <node label="test.pdf" url="test.pdf" pic="pdf"
    info="test text." />
    </node>
    <node label="» Links - document">
    <node label="test URL" url="
    http://www." pic="ie" info="test text."
    />
    <node label="test URL" url="
    http://www." pic="ie" info="test text."
    />
    </node>
    </node>

    Solved it ..works nicely :D
    ty anyways.
    //cleaner
    "cLeAnEr" <[email protected]> skrev i meddelandet
    news:ekm1vc$r8h$[email protected]..
    > hi all.
    >
    > I´ve just completed a little test for making a tree
    component with custom
    > icons / bransch.
    > However, i can only get my first branch to show custom
    icons.(links -
    > document) I figure I need to make a nested loop to
    Iterate over
    > nextSibling?. I tried ALOT, but i guess I´m doing
    something completely
    > wrong.
    >
    >
    > here is code for my tree so far:
    >
    > my_xml = new XML();
    > my_xml.ignoreWhite = true;
    > my_xml.load("tree.xml");
    >
    > my_xml.onLoad = function(){
    > myTree.dataProvider = this.firstChild;
    >
    >
    > var folders = my_xml.firstChild.firstChild;
    > var docs = folders.childNodes;
    >
    > for (var i=0; i < docs.length; i++){
    > currDoc = docs
    > trace(docs);
    >
    > var docIcon = currDoc.attributes.pic;
    >
    > switch(docIcon){
    > case "pdf":
    > myTree.setIcon(currDoc, "pdfIcon");
    > break;
    > case "word":
    > myTree.setIcon(currDoc, "wordIcon");
    > break;
    > case "excel":
    > myTree.setIcon(currDoc, "excelIcon");
    > break;
    > case "ie":
    > myTree.setIcon(currDoc, "ieIcon");
    > break;
    > }//switch
    > } //for
    > };//onLoad
    >
    >
    > And here is the XML I used:
    >
    > <node label="» Dokument typer">
    > <node label="» links - document">
    > <node label="test.url" url="
    http://www." pic="ie" info="test text" />
    > <node label="test.doc" url="test.doc" pic="word"
    info="test text" />
    > <node label="test.excel" url="test.xls" pic="excel"
    info="test text" />
    > <node label="test.pdf" url="test.pdf" pic="pdf"
    info="test text." />
    > </node>
    > <node label="» Links - document">
    > <node label="test URL" url="
    http://www." pic="ie" info="test text."
    />
    > <node label="test URL" url="
    http://www." pic="ie" info="test text."
    />
    > </node>
    > </node>
    >

  • Too many nested loops in execution plan?

    Hi,
    i wonder about execution plan not indicating that access to some tables (for join) is in parallel.
    Please see this example:
    ------------------------ snip ------------------------------------
    drop table test_a1;
    drop table test_a2;
    drop table test_b;
    drop table test_c;
    drop table test_d;
    create table test_a1 (
    x number,
    y number,
    z number);
    create unique index testa1_pk on test_a1 (x);
    create table test_a2 (
    x number,
    y number,
    z number);
    create unique index testa2_pk on test_a2 (x);
    create table test_b (
    x number,
    y number,
    z number);
    create unique index testb_pk on test_b (y);
    create table test_c (
    x number,
    y number,
    z number);
    create unique index testc_pk on test_b (z);
    create table test_d (
    x number,
    y number,
    z number);
    create unique index testd_pk on test_d (y);
    select
    a1.x a1_x,
    a1.y a1_y,
    a1.z a1_z,
    a2.x a2_x,
    a2.y a2_y,
    a2.z a2_z,
    b.x b_x,
    b.y b_y,
    b.z b_z,
    c.x c_x,
    c.y c_y,
    c.z c_z,
    d.x d_x,
    d.y d_y,
    d.z d_z
    from test_a1 a1, test_a2 a2, test_b b, test_c c, test_d d
    where a1.x = 100
    and a2.x = 200
    and b.y = a1.y
    and c.z = b.z
    and d.y = a1.y;
    ------------------------ snap ------------------------------------
    The execution plan goes like this:
    Select Stmt
         nested loops
              nested loops
                   nested loops
                        nested loops
                             table access
                                  index
                                       access predicate
                                            a2.x = 200
                             table access
                                  index
                                       access predicate
                                            a1.x = 100
                        table access
                             index
                                  access predicate
                                       d.y = a1.y
                   table access
                        index
                             access predicate
                                  b.y = a1.y
              table acess
                   index
                        acess predicate
                             c.z = b.z
    Access to tables a1 and a2 is on the same level (in parallel - i guess).
    However, why isn't access to table d and b on the same level?
    Both depend on a1. So no need to execute one after the other (no inter-dependency).
    Maybe i have just wrong expectation to the output of the execution plan(?!)
    - many thanks!
    best regards,
    Frank

    Preservation of identation and spacing is invaluable when it comes to reading an explain plan.
    | Id  | Operation                       | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT                |           |     1 |   195 |     2   (0)| 00:00:01 |
    |   1 |  NESTED LOOPS                   |           |     1 |   195 |     2   (0)| 00:00:01 |
    |   2 |   NESTED LOOPS                  |           |     1 |   156 |     0   (0)| 00:00:01 |
    |   3 |    NESTED LOOPS                 |           |     1 |   117 |     0   (0)| 00:00:01 |
    |   4 |     NESTED LOOPS                |           |     1 |    78 |     0   (0)| 00:00:01 |
    |   5 |      TABLE ACCESS BY INDEX ROWID| TEST_A2   |     1 |    39 |     0   (0)| 00:00:01 |
    |*  6 |       INDEX UNIQUE SCAN         | TESTA2_PK |     1 |       |     0   (0)| 00:00:01 |
    |   7 |      TABLE ACCESS BY INDEX ROWID| TEST_A1   |     1 |    39 |     0   (0)| 00:00:01 |
    |*  8 |       INDEX UNIQUE SCAN         | TESTA1_PK |     1 |       |     0   (0)| 00:00:01 |
    |   9 |     TABLE ACCESS BY INDEX ROWID | TEST_D    |    82 |  3198 |     0   (0)| 00:00:01 |
    |* 10 |      INDEX UNIQUE SCAN          | TESTD_PK  |     1 |       |     0   (0)| 00:00:01 |
    |  11 |    TABLE ACCESS BY INDEX ROWID  | TEST_B    |    82 |  3198 |     0   (0)| 00:00:01 |
    |* 12 |     INDEX UNIQUE SCAN           | TESTB_PK  |     1 |       |     0   (0)| 00:00:01 |
    |* 13 |   TABLE ACCESS FULL             | TEST_C    |     1 |    39 |     2   (0)| 00:00:01 |
    Predicate Information (identified by operation id):
       6 - access("A2"."X"=200)
       8 - access("A1"."X"=100)
      10 - access("D"."Y"="A1"."Y")
      12 - access("B"."Y"="A1"."Y")
      13 - filter("C"."Z"="B"."Z")
    Access to tables a1 and a2 is on the same level (in parallel - i guess).
    Maybe i have just wrong expectation to the output of the execution plan(?!)You guess wrong, there's nothing parallel going on here.
    Execution plan is a tree of parent-child operations.
    For example, the NESTED LOOP at operation 4 has two children @ 5 and 7.
    Both of these operations- 5 & 7 - have a single child operation.
    The execution tree starts with operation 6, using the TESTA2_PK index to identify rows where A2.X=100.
    From this list of rowids, we go to the table TEST_A2 operation 5.
    The rows from operation five feed into the NESTED LOOP - operation 4.
    For each of these rows, we go to TEST_A1 via the index TEST_A1_PK for rows where A1.X=100.
    This is really a cartesian join because there's no join condition between the two tables.
    etc, etc, etc
    Three things in particular to point out.
    Firstly, that nothing joins to A2. So there will be a cartesian product - i.e. for every row in the result set between the joined tables A1, B, C and D, these will be multiplied by the number of rows returned by the the A2 rowsource.
    Secondly, when everything has got one or zero rows (or the optimizer thinks that it's one or zero rows), you can get very different plans from when there are known/thought to be more rows.
    Both depend on a1. So no need to execute one after the other (no inter-dependency).Thirdly, in terms of isolated join operations (ignoring A2 and C for the moment), A1 cannot join to B and D at the same time, you can either join A1 to B and then join the result of that to D, or join A1 to D then B, which is what you've got in your plan (well, actually we have A2 joined to A1 then the result of that joined to D and then the result of that to B).
    Edited by: Dom Brooks on Jul 6, 2011 4:07 PM
    Corrected typo

  • Why optimizer prefers nested loop over hash join?

    What do I look for if I want to find out why the server prefers a nested loop over hash join?
    The server is 10.2.0.4.0.
    The query is:
    SELECT p.*
        FROM t1 p, t2 d
        WHERE d.emplid = p.id_psoft
          AND p.flag_processed = 'N'
          AND p.desc_pool = :b1
          AND NOT d.name LIKE '%DUPLICATE%'
          AND ROWNUM < 2tkprof output is:
    Production
    call     count       cpu    elapsed       disk      query    current        rows
    Parse        1      0.01       0.00          0          0          4           0
    Execute      1      0.00       0.01          0          4          0           0
    Fetch        1    228.83     223.48          0    4264533          0           1
    total        3    228.84     223.50          0    4264537          4           1
    Misses in library cache during parse: 1
    Optimizer mode: ALL_ROWS
    Parsing user id: 108  (SANJEEV)
    Rows     Row Source Operation
          1  COUNT STOPKEY (cr=4264533 pr=0 pw=0 time=223484076 us)
          1   NESTED LOOPS  (cr=4264533 pr=0 pw=0 time=223484031 us)
      10401    TABLE ACCESS FULL T1 (cr=192 pr=0 pw=0 time=228969 us)
          1    TABLE ACCESS FULL T2 (cr=4264341 pr=0 pw=0 time=223182508 us)Development
    call     count       cpu    elapsed       disk      query    current        rows
    Parse        1      0.01       0.00          0          0          0           0
    Execute      1      0.00       0.01          0          4          0           0
    Fetch        1      0.05       0.03          0        512          0           1
    total        3      0.06       0.06          0        516          0           1
    Misses in library cache during parse: 1
    Optimizer mode: ALL_ROWS
    Parsing user id: 113  (SANJEEV)
    Rows     Row Source Operation
          1  COUNT STOPKEY (cr=512 pr=0 pw=0 time=38876 us)
          1   HASH JOIN  (cr=512 pr=0 pw=0 time=38846 us)
         51    TABLE ACCESS FULL T2 (cr=492 pr=0 pw=0 time=30230 us)
        861    TABLE ACCESS FULL T1 (cr=20 pr=0 pw=0 time=2746 us)

    sanjeevchauhan wrote:
    What do I look for if I want to find out why the server prefers a nested loop over hash join?
    The server is 10.2.0.4.0.
    The query is:
    SELECT p.*
    FROM t1 p, t2 d
    WHERE d.emplid = p.id_psoft
    AND p.flag_processed = 'N'
    AND p.desc_pool = :b1
    AND NOT d.name LIKE '%DUPLICATE%'
    AND ROWNUM < 2
    You've got already some suggestions, but the most straightforward way is to run the unhinted statement in both environments and then force the join and access methods you would like to see using hints, in your case probably "USE_HASH(P D)" in your production environment and "FULL(P) FULL(D) USE_NL(P D)" in your development environment should be sufficient to see the costs and estimates returned by the optimizer when using the alternate access and join patterns.
    This give you a first indication why the optimizer thinks that the chosen access path seems to be cheaper than the obviously less efficient plan selected in production.
    As already mentioned by Hemant using bind variables complicates things a bit since EXPLAIN PLAN is not reliable due to bind variable peeking performed when executing the statement, but not when explaining.
    Since you're already on 10g you can get the actual execution plan used for all four variants using DBMS_XPLAN.DISPLAY_CURSOR which tells you more than the TKPROF output in the "Row Source Operation" section regarding the estimates and costs assigned.
    Of course the result of your whole exercise might be highly dependent on the actual bind variable value used.
    By the way, your statement is questionable in principle since you're querying for the first row of an indeterministic result set. It's not deterministic since you've defined no particular order so depending on the way Oracle executes the statement and the physical storage of your data this query might return different results on different runs.
    This is either an indication of a bad design (If the query is supposed to return exactly one row then you don't need the ROWNUM restriction) or an incorrect attempt of a Top 1 query which requires you to specify somehow an order, either by adding a ORDER BY to the statement and wrapping it into an inline view, or e.g. using some analytic functions that allow you specify a RANK by a defined ORDER.
    This is an example of how a deterministic Top N query could look like:
    SELECT
    FROM
    SELECT p.*
        FROM t1 p, t2 d
        WHERE d.emplid = p.id_psoft
          AND p.flag_processed = 'N'
          AND p.desc_pool = :b1
          AND NOT d.name LIKE '%DUPLICATE%'
    ORDER BY <order_criteria>
    WHERE ROWNUM <= 1;Regards,
    Randolf
    Oracle related stuff blog:
    http://oracle-randolf.blogspot.com/
    SQLTools++ for Oracle (Open source Oracle GUI for Windows):
    http://www.sqltools-plusplus.org:7676/
    http://sourceforge.net/projects/sqlt-pp/

  • Nested loop vs Hash Join

    Hi,
    Both the querys are returning same results, but in my first query hash join and second query nested loop . How ? PLs explain
    select *
    from emp a,dept b
    where a.deptno=b.deptno and b.deptno>20;
    6 rows
    Plan hash value: 4102772462
    | Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT             |         |     6 |   348 |     6  (17)| 00:00:01 |
    |*  1 |  HASH JOIN                   |         |     6 |   348 |     6  (17)| 00:00:01 |
    |   2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     3 |    60 |     2   (0)| 00:00:01 |
    |*  3 |    INDEX RANGE SCAN          | PK_DEPT |     3 |       |     1   (0)| 00:00:01 |
    |*  4 |   TABLE ACCESS FULL          | EMP     |     7 |   266 |     3   (0)| 00:00:01 |
    Predicate Information (identified by operation id):
       1 - access("A"."DEPTNO"="B"."DEPTNO")
       3 - access("B"."DEPTNO">20)
       4 - filter("A"."DEPTNO">20)
    select *
    from emp a,dept b
    where a.deptno=b.deptno and b.deptno=30;  
    6 rows
    Plan hash value: 568005898
    | Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT             |         |     5 |   290 |     4   (0)| 00:00:01 |
    |   1 |  NESTED LOOPS                |         |     5 |   290 |     4   (0)| 00:00:01 |
    |   2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    20 |     1   (0)| 00:00:01 |
    |*  3 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |
    |*  4 |   TABLE ACCESS FULL          | EMP     |     5 |   190 |     3   (0)| 00:00:01 |
    Predicate Information (identified by operation id):
       3 - access("B"."DEPTNO"=30)
       4 - filter("A"."DEPTNO"=30)

    Hi,
    Unless specifically requested, Oracle picks the best execution plan based on estimates of table sizes, column selectivity and many other variables. Even though Oracle does its best to have the estimates as accurate as possible, they are frequently different, and in some cases quite different, from the actual values.
    In the first query, Oracle estimated that the predicate “ b.deptno>20” would limit the number of records to 6, and based on that it decided the use Hash Join.
    In the second query, Oracle estimated that the predicate “b.deptno=30” would limit the number of records to 5, and based on that it decided the use Nested Loops Join.
    The fact that the actual number of records is the same is irrelevant because Oracle used the estimate, rather the actual number of records to pick the best plan.
    HTH,
    Iordan
    Iotzov

  • Hash join vs nested loop

    DECLARE @tableA table (Productid varchar(20),Product varchar(20),RateID int)
    insert into @tableA values('1','Mobile',2);
    insert into @tableA values('2','Chargers',4);
    insert into @tableA values('3','Stand',6);
    insert into @tableA values('4','Adapter',8);
    insert into @tableA values('5','Cover',10);
    insert into @tableA values('6','Protector',12);
    --SELECT * FROM @tableA
    DECLARE @tableB table (id varchar(20),RateID int,Rate int)
    insert into @tableB values('1',2,200);
    insert into @tableB values('2',4,40);
    insert into @tableB values('3',6,60);
    insert into @tableB values('4',8,80);
    insert into @tableB values('5',10,10);
    insert into @tableB values('6',12,15);
    --SELECT * FROM @tableB
    SELECT Product,Rate
    FROM @tableA a
    JOIN @tableB b ON a.RateID = b.RateID
    Above is the sample query, where in execution plan it shows the Hash Match (inner Join). Now how do I change it to Nested Loop with out changing the query? help plz

    Is Hash Match(inner join) or Nested loop is better to have in the query?
    That depends on the size of the tables, available indexes etc. The optimizer will (hopefully) make the best choice.
    Above is the sample query, where in execution plan it shows the Hash Match (inner Join). Now how do I change it to Nested Loop with out changing the query?
    The answer that you should leave that to the optimizer in most cases.
    I see that the logical read for nested loop is higher than Hash Match.
    But Hash Match tends to need more CPU. The best way to two compare two queries or plans is wallclock time.
    On a big tables, how do we reduce the logical read? 
    Make sure that there are usable indexes.
    Erland Sommarskog, SQL Server MVP, [email protected]

  • HASH JOIN or NESTED LOOP

    I've been asked to check if HASH JOIN is more suitable than NESTED LOOP(which CBO chose by default) for the following query.
    SELECT CM_DETAILS.TASK_ID FROM GEN_TYPE, CM_DETAILS WHERE ( ( ( ( ( CM_DETAILS.STAT_CODE < 8 ) AND ( GEN_TYPE.TASK_ID = CM_DETAILS.TASK_ID ) ) AND ( GEN_TYPE.DEST_LOCN_ID = 5 ) ) AND ( GEN_TYPE.COM_ID = 7 ) ) AND ( ( ( CM_DETAILS.CASE_NO = 1 ) OR ( CM_DETAILS.CASE_NO = 3 ) ) OR ( CM_DETAILS.CASE_NO = 9 ) ) )
    Both GEN_TYPE and CM_DETAILS tables have over 330,000 rows.
    Version: 10g R2
    Any thoughts?

    As gintsp gave you very nice tip but there is initialization parameter "     OPTIMIZER_INDEX_COST_ADJ" which cause what path to be chose for CBO,but usually expert says for changing init paramter setting should be at last resort.
    It has default value of 100 which indicates to the CBO that indexed access is 100% as costly (i.e., equally costly) as FULL table scan access.
    SQL> column plan_plus_exp format a100
    SQL> set linesize 1000
    SQL> SET AUTOTRACE TRACEONLY
    SQL> SELECT e.ename,d.dname
      2    FROM emp e,dept d
      3   WHERE e.deptno=d.deptno
      4  /
    14 rows selected.
    Execution Plan
       0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=7 Card=10 Bytes=320)
       1    0   HASH JOIN (Cost=7 Card=10 Bytes=320)
       2    1     TABLE ACCESS (FULL) OF 'DEPT' (TABLE) (Cost=3 Card=5 Bytes=90)
       3    1     TABLE ACCESS (FULL) OF 'EMP' (TABLE) (Cost=3 Card=14 Bytes=196)
    Statistics
            672  recursive calls
              0  db block gets
            151  consistent gets
             27  physical reads
              0  redo size
            793  bytes sent via SQL*Net to client
            508  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
             15  sorts (memory)
              0  sorts (disk)
             14  rows processed
    SQL> /
    14 rows selected.
    Execution Plan
       0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=7 Card=10 Bytes=320)
       1    0   HASH JOIN (Cost=7 Card=10 Bytes=320)
       2    1     TABLE ACCESS (FULL) OF 'DEPT' (TABLE) (Cost=3 Card=5 Bytes=90)
       3    1     TABLE ACCESS (FULL) OF 'EMP' (TABLE) (Cost=3 Card=14 Bytes=196)
    Statistics
              0  recursive calls
              0  db block gets
             15  consistent gets
              0  physical reads
              0  redo size
            793  bytes sent via SQL*Net to client
            508  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
             14  rows processed
    SQL> SHOW PARAMETER optimizer
    NAME                                 TYPE                             VALUE
    optimizer_dynamic_sampling           integer                          2
    optimizer_features_enable            string                           10.1.0
    optimizer_index_caching              integer                          0
    optimizer_index_cost_adj             integer                          100<--------
    optimizer_mode                       string                           ALL_ROWS
    SQL> ALTER SESSION SET optimizer_index_cost_adj=35
      2  /
    Session altered.
    SQL> SELECT e.ename,d.dname
      2    FROM emp e,dept d
      3   WHERE e.deptno=d.deptno
      4  /
    14 rows selected.
    Execution Plan
       0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=5 Card=10 Bytes=320)
       1    0   MERGE JOIN (Cost=5 Card=10 Bytes=320)
       2    1     TABLE ACCESS (BY INDEX ROWID) OF 'DEPT' (TABLE) (Cost=1 Card=5 Bytes=90)
       3    2       INDEX (FULL SCAN) OF 'DEPT_PRIMARY_KEY' (INDEX (UNIQUE)) (Cost=1 Card=5)
       4    1     SORT (JOIN) (Cost=4 Card=14 Bytes=196)
       5    4       TABLE ACCESS (FULL) OF 'EMP' (TABLE) (Cost=3 Card=14 Bytes=196)
    Statistics
              1  recursive calls
              0  db block gets
             11  consistent gets
              1  physical reads
              0  redo size
            733  bytes sent via SQL*Net to client
            508  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              1  sorts (memory)
              0  sorts (disk)
             14  rows processed
    SQL> /
    14 rows selected.
    Execution Plan
       0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=5 Card=10 Bytes=320)
       1    0   MERGE JOIN (Cost=5 Card=10 Bytes=320)
       2    1     TABLE ACCESS (BY INDEX ROWID) OF 'DEPT' (TABLE) (Cost=1 Card=5 Bytes=90)
       3    2       INDEX (FULL SCAN) OF 'DEPT_PRIMARY_KEY' (INDEX (UNIQUE)) (Cost=1 Card=5)
       4    1     SORT (JOIN) (Cost=4 Card=14 Bytes=196)
       5    4       TABLE ACCESS (FULL) OF 'EMP' (TABLE) (Cost=3 Card=14 Bytes=196)
    Statistics
              0  recursive calls
              0  db block gets
             11  consistent gets
              0  physical reads
              0  redo size
            733  bytes sent via SQL*Net to client
            508  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              1  sorts (memory)
              0  sorts (disk)
             14  rows processedKhurram

  • Oracle 11g - Nested loops on outer joins

    Hello,
    I have a select query that was working with no problems. The results are used to insert data into a temp table.
    Recently, it would not complete executing. The explain plan shows a cartesian. But, there could be problems with using nested loops on the outer join. Interestingly, when I copy production code and rename the temp table and rename the view, it works.
    Can someone take a look at the code and help. Maybe offer a suggestion on tuning too? Thanks.
    CREATE TABLE "CT"
    ( "TN" VARCHAR2(30) NOT NULL ENABLE,
    "COL_NAME" VARCHAR2(30) NOT NULL ENABLE,
    "CDE" VARCHAR2(5) NOT NULL ENABLE,
    "CDE_DESC" VARCHAR2(80) NOT NULL ENABLE,
    "CDE_STAT" CHAR(1));
    insert into CT (TN, COL_NAME, CDE, CDE_DESC, CDE_STAT)
    values ('INDSD', 'STCD', 'U', 'RF', 'A');
    insert into CT (TN, COL_NAME, CDE, CDE_DESC, CDE_STAT)
    values ('AT', 'TCD', '001', 'RL', 'A');
    insert into CT (TN, COL_NAME, CDE, CDE_DESC, CDE_STAT)
    values ('AT', 'TCD', '033', 'PFR', 'A');
    CREATE TABLE "IPP"
    ( "IND_ID" NUMBER(9,0) NOT NULL ENABLE,
    "PLCD" VARCHAR2(5) NOT NULL ENABLE,
    "CBCD" VARCHAR2(5));
    insert into IPP (IND_ID, PLCD, CBCD)
    values (2007, 'AS', '04');
    insert into IPP (IND_ID, PLCD, CBCD)
    values (797098, 'AS', '34');
    insert into IPP (IND_ID, PLCD, CBCD)
    values (797191, 'AS','04');
    CREATE TABLE "INDS"
    ( "OPCD" VARCHAR2(5) NOT NULL ENABLE,
    "IND_ID" NUMBER(9,0) NOT NULL ENABLE,
    "IND_CID" NUMBER(*,0),
    "GFLG" VARCHAR2(1),
    "HHID" NUMBER(9,0),
    "DOB" DATE,
    "DOB_FLAG" VARCHAR2(1),
    "VCD" VARCHAR2(5),
    "VTDTE" DATE,
    "VPPCD" VARCHAR2(4),
    "VRCDTE" DATE NOT NULL ENABLE,
    "VDSID" NUMBER(9,0),
    "VTRANSID" NUMBER(12,0),
    "VOWNCD" VARCHAR2(5),
    "RCDTE" DATE,
    "LRDTE" DATE
    insert into INDS (OPCD, IND_ID, IND_CID, GFLG, HHID, DOB, DOB_FLAG, VCD, VTDTE, VPPCD, VRCDTE, VDSID, VTRANSID, VOWNCD, RCDTE, LRDTE)
    values ('USST', 2007, 114522319, '', 304087673, to_date('01-01-1980', 'dd-mm-yyyy'), 'F', '2', to_date('06-04-2011 09:21:37', 'dd-mm-yyyy hh24:mi:ss'), '', to_date('06-04-2011 09:21:37', 'dd-mm-yyyy hh24:mi:ss'), 1500016, null, 'USST', to_date('06-04-2011 09:21:37', 'dd-mm-yyyy hh24:mi:ss'), to_date('18-07-2012 21:52:53', 'dd-mm-yyyy hh24:mi:ss'));
    insert into INDS (OPCD, IND_ID, IND_CID, GFLG, HHID, DOB, DOB_FLAG, VCD, VTDTE, VPPCD, VRCDTE, VDSID, VTRANSID, VOWNCD, RCDTE, LRDTE)
    values ('USST', 304087678, 115242519, '', 304087678, to_date('01-01-1984', 'dd-mm-yyyy'), 'F', '2', to_date('06-04-2011 09:21:39', 'dd-mm-yyyy hh24:mi:ss'), '', to_date('06-04-2011 09:21:39', 'dd-mm-yyyy hh24:mi:ss'), 1500016, null, 'USST', to_date('06-04-2011 09:21:39', 'dd-mm-yyyy hh24:mi:ss'), to_date('18-07-2012 21:52:53', 'dd-mm-yyyy hh24:mi:ss'));
    CREATE TABLE "INDS_TYPE"
    ( "IND_ID" NUMBER(9,0) NOT NULL ENABLE,
    "STCD" VARCHAR2(5) NOT NULL ENABLE);
    insert into INDS_type (IND_ID, STCD)
    values (2007, 'U');
    insert into INDS_type (IND_ID, STCD)
    values (313250322, 'U');
    insert into INDS_type (IND_ID, STCD)
    values (480058122, 'U');
    CREATE TABLE "PLOP"
    ( "OPCD" VARCHAR2(5) NOT NULL ENABLE,
    "PLCD" VARCHAR2(5) NOT NULL ENABLE,
    "PPLF" VARCHAR2(1));
    insert into PLOP (OPCD, PLCD, PPLF)
    values ('USST', 'SP', 'Y');
    insert into PLOP (OPCD, PLCD, PPLF)
    values ('PMUSA', 'ST', '');
    insert into PLOP (OPCD, PLCD, PPLF)
    values ('USST', 'RC', '');
    CREATE TABLE "IND_T"
    ( "OPCD" VARCHAR2(5) NOT NULL ENABLE,
    "CID" NUMBER(9,0) NOT NULL ENABLE,
    "CBCD" VARCHAR2(5),
    "PF" VARCHAR2(1) NOT NULL ENABLE,
    "DOB" DATE,
    "VCD" VARCHAR2(5),
    "VOCD" VARCHAR2(5),
    "IND_CID" NUMBER,
    "RCDTE" DATE NOT NULL ENABLE
    insert into IND_T (OPCD, CID, CBCD,PF, DOB, VCD, VOCD, IND_CID, RCDTE)
    values ('JMC', 2007, '04', 'F',to_date('11-10-1933', 'dd-mm-yyyy'), '2', 'PMUSA', 363004880, to_date('30-09-2009 04:31:34', 'dd-mm-yyyy hh24:mi:ss'));
    insert into IND_T (OPCD, CID, CBCD,PF, DOB, VCD, VOCD, IND_CID, RCDTE)
    values ('JMC', 2008, '04', 'N',to_date('01-01-1980', 'dd-mm-yyyy'), '2', 'PMUSA', 712606335, to_date('05-04-2013 19:36:05', 'dd-mm-yyyy hh24:mi:ss'));
    CREATE TABLE "IC"
    ( "CID" NUMBER(9,0) NOT NULL ENABLE,
    "CF" CHAR(1));
    insert into IC (CID, CF)
    values (2007, 'N');
    insert into IC (CID, CF)
    values (100, 'N');
    insert into IC (CID, CF)
    values (200, 'N');
    CREATE OR REPLACE FORCE VIEW "INDSS_V" ("OPCD", "IND_ID", "IND_CID", "GFLG", "HHID", "DOB", "DOB_FLAG", "VCD", "VTDTE", "VPPCD", "VRCDTE", "VDSID", "VTRANSID", "VOWNCD", "RCDTE", "LRDTE") AS
    SELECT DISTINCT a.OPCD, a.IND_ID, a.IND_CID, a.GFLG, a.HHID,
    a.DOB, a.DOB_flag, a.VCD, a.VTDTE,
    a.VPPCD, a.VRCDTE, a.VDSID, a.VTRANSID,
    a.VOWNCD, a.RCDTE, a.LRDTE
    FROM INDS a, INDS_type b
    WHERE a.IND_ID = b.IND_ID
    AND b.STCD in (select CDE
    from CT --database link
    where TN = 'INDSD'
    and COL_NAME = 'STCD'
    and CDE_STAT = 'A') ;
    --insert /*+ parallel(IND_T,2) */ into IND_T
    select /*+ parallel(a,4) */
    a.OPCD as OPCD
    , a.IND_ID as CID
    , b.CBCD as CBCD
    , NULL as BFCD
    , 'N' as PF
    , a.DOB as DOB
    , a.VCD as VCD
    , a.VOWNCD as VOCD
    , a.IND_CID as IND_CID
    , a.RCDTE as RCDTE
    from INDSS_V a
    , (select /*+ parallel(IPP,4) */ * from IPP IPP , PLOP PLO
    where plo.PLCD = ipp.PLCD
    and PPLF='Y') b
    , IC c
    where a.IND_ID = b.IND_ID (+)
    and a.OPCD = b.OPCD (+)
    and a.IND_ID = c.CID
    and c.CF = 'N';

    Please consult
    HOW TO: Post a SQL statement tuning request - template posting
    Also format your code and post it using the [ code ] and [ /code ] tags. (Leave out the extra space after [ and before ])
    Sybrand Bakker
    Senior Oracle DBA
    Edited by: sybrand_b on 10-apr-2013 17:57

Maybe you are looking for

  • Setting Destination URI of a Pie Chart Graph Programatically-OA Framework

    Hi All, I have created a OF Page with the following Regions one under the other: 1. PageLayoutRN 2. HideShowHdr1 - Hide/Show Header 3. TblLayout1RN - Table Layout 4. Tbl1RowLayout1RN - Table Row Layout 5. Row1CellFormat1RN - Cell Format 6. Row2CellFo

  • Syncing logic express 9 with akai mpk61

    hey guys, i need some advice syncing akai mpk 61 or 49 midi controller with logics timecode, any suggestions or pdf's u can send me, cheers, peter

  • Thinking of changing to BT

    Hi, we are currently with sky for everything but are looking to change. Looking for any advice that can sway our decision. Something to take into consideration is that we have a 9yr old who watches kids programmes. I have 'chatted' to BT but am confu

  • IBooks screen dim only works on 3/4 of screen

    I Just upgraded to ipad os 813 and now in iBooks whe reading a book, if I want to set brightness to its lowest setting it applies this to only 3/4 of the screen. See attached screen shot. I would appreciate any help on how to fix or if this is a big

  • How to get two date difference in Day/hour/min/secs pl

    First of all, Hello to All, i am new to Oracle DB, but i have little experience in Other Database such as Sybase, sql server etc please kindly help me in DoctorChart table i have DocName,Id#,Citcotype,Medtype,AdmitDate,DischargeDate(both admitdate &