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                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           

Similar Messages

  • 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

  • Hash partitioning v. list partitioning on surrogate key + partition pruning

    Hi,
    Have a large fact table with surrogate keys, therefore queries are of form
    select dimension.attribute..
    from fact, dima, dimb..
    where facta.dima_surrogate_key = dima.dimension_key
    and facta.dimb_surrogate_key = dimb.dimension_key
    and dima.attribute = <value>
    and dimb.attribute = <value>
    Would ideally like partition pruning to happen but will this happen if hash partition on facta.surrogate_key
    Likewise could list partition on facta.dima_surrogate_key and further sub-partition on hash of factb.dima_surrogate_key.
    Any advice much appreciated.

    user5716448 wrote:
    Hi,
    Version 11.2.0.1
    fact table structure
    PRODUCT_ID NUMBER
    RETAILER_ID NUMBER
    OUTLET_ID NUMBER
    CALENDAR_ID NUMBER
    BRANCH_ID NUMBER
    PUBLISHER_ID NUMBER
    DISTRIBUTOR_ID NUMBER
    TRANS_TYPE_ID NUMBER
    TRANS_QTY NUMBER (10)
    TRANS_VALUE (10,4)
    No date on fact table (just surrogate_id for calendar whihc links to calendar/date dimension.
    Although queries can be by date of transaction, most aren't.
    Potential to grow to 3 billion rows.
    Considering hash partitioning on the product_id, simply to break data down and product_id is the largest dimension.About hash partitioning – in this case it is probably all about the ability to run in parallel. Do not have any info on that, so I cannot comment further.
    >
    sqls are varied, lots of different types some query all dimensions, sometimes a few. Not the straightforward date examples in the manual.You can pick a dimension that is frequently used by the SQLs. I understand that there is no perfect one, but even if you pick just a “good” one you might have a good deal of partition elimination.
    >
    Users run 3rd part ad-hoc reporting layer which has to allow them to report against the star in any way they want.
    Star transformation hint enabled. Have heard in deciding number of hash partitions, partition size should geneerally be < 2gb.
    e.g transactions for a given product for customers belonging to a given multiple in a given week
    select trans_qty, trans_value, m.prod_name, m.prod_num, r.cust_name, w.branch_name, rtt.trans_date, rtt,trans_type
    from retailer_transaction rt, media m, wholesaler w, calendar c, retailer r, trans_type rtt
    where rt.issue_id = m.dimension_key
    and m.prod_num = 600
    and rt.branch_id = w.dimension_key
    and rt.outlet_id = r.dimension_key
    and r.multiple_num = 700
    and rt.calendar_id = calendar.dimension_key
    and m.issue_year_week = 201110
    and rt.trans_type_id = rtt.dimension_keyLastly, you need to focus on weather and how to partition your indexes (I assume you have bunch of bitmaps). This decision is at least as important as partitioning the table.

  • 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

  • Star transformation and Partition pruning

    All experts,
    I need advice on my situation -
    I have data warehouse running on oracle 11.2.0.1
    We are using star trnasformation. The fact table is partitioned.
    However, with the star query (fact joined to dimensions with keys and filters only on dimensions), partition pruning is not happening.
    I read some documents online and it seems that partition pruning is not going to happen unless I directly filter fact (which is against the best paractices of star query).
    Please advice

    SELECT
    PTL_EDW.D_TIME.CAL_YYYYMM,
    (( ( ( sum(PTL_EDWPERF.F_JOB_OIL_COST.LABOR_COST) )+( sum(PTL_EDWPERF.F_JOB_OIL_COST.OUTSIDE_COST) )+( sum(PTL_EDWPERF.F_JOB_OIL_COST.PARTS_COST) ) )-( ( sum(PTL_EDWPERF.F_JOB_OIL_COST.RECOVERY_LABOR_AMOUNT) )+( sum(PTL_EDWPERF.F_JOB_OIL_COST.RECOVERY_OUTSIDE_AMOUNT) )+( sum(PTL_EDWPERF.F_JOB_OIL_COST.RECOVERY_PARTS_AMOUNT) ) )+( ( sum(PTL_EDWPERF.F_JOB_OIL_COST.WARRANTY_LABOR_AMOUNT) )+( sum(PTL_EDWPERF.F_JOB_OIL_COST.WARRANTY_OUTSIDE_AMOUNT) )+( sum(PTL_EDWPERF.F_JOB_OIL_COST.WARRANTY_PARTS_AMOUNT) ) ) )+( sum(PTL_EDWPERF.F_JOB_OIL_COST.OIL_COST) ))
    FROM
    PTL_EDWPERF.F_JOB_OIL_COST,
    PTL_EDW.D_LOCATION_MASTER D_LOCATION_DOMICILE,
    PTL_EDW.D_VEHICLE_CAP_STATUS,
    PTL_EDW.D_UNIT_MASTER,
    PTL_EDW.D_ACCOUNT_CODE,
    PTL_EDW.D_TIME
    WHERE
    ( PTL_EDWPERF.F_JOB_OIL_COST.ACCOUNT_CODE_KEY = PTL_EDW.D_ACCOUNT_CODE.ACCOUNT_CODE_KEY)
    AND ( PTL_EDWPERF.F_JOB_OIL_COST.VEHICLE_CAP_STATUS_KEY=PTL_EDW.D_VEHICLE_CAP_STATUS.VEHICLE_CAP_STATUS_KEY )
    AND ( PTL_EDWPERF.F_JOB_OIL_COST.CHARGING_LOCATION_KEY=D_LOCATION_DOMICILE.LOCATION_MASTER_KEY )
    AND (PTL_EDWPERF.F_JOB_OIL_COST.UNIT_MASTER_KEY = PTL_EDW.D_UNIT_MASTER.UNIT_MASTER_KEY)
    AND (PTL_EDWPERF.F_JOB_OIL_COST.RO_ACCOUNTING_MONTH_KEY = PTL_EDW.D_TIME.TIME_KEY)
    AND ( exists (select 1 from ptl_edw.s_location where s_location.ssoid = '600028988' and PTL_EDWPERF.F_JOB_OIL_COST.CHARGING_LOCATION_KEY = decode(s_location.location_master_key, -99999, PTL_EDWPERF.F_JOB_OIL_COST.CHARGING_LOCATION_KEY, s_location.location_master_key)) )
    AND
    --PTL_EDWPERF.F_JOB_OIL_COST.PARTITION_KEY  BETWEEN  201011  AND  201104
    PTL_EDW.D_TIME.CAL_YYYYMM BETWEEN 200601 AND 201104
    AND
    D_LOCATION_DOMICILE.CORP_CD IN ( '2000','HPTL' )
    AND
    ( ( PTL_EDW.D_VEHICLE_CAP_STATUS.VEHICLE_CAP_STATUS ) IN ( 'ACCRUED','ACTIVE' ) )
    AND
    ( PTL_EDW.D_UNIT_MASTER.CONTRACT_GROUP = 'P' )
    AND
    PTL_EDW.D_UNIT_MASTER.UNIT_CATEGORY IN ( 'TRACTOR','TRAILER','TRUCK' )
    AND
    PTL_EDW.D_ACCOUNT_CODE.ACCOUNT_CODE_GROUP1 IN ( 'COMMERCIAL RENTAL','CONTRACT MAINTENANCE - GUAR','CONTRACT MAINTENANCE - OTHER','CONTRACT MAINTENANCE - PEG','LEASE','TRAILER PLUS' )
    GROUP BY
    PTL_EDW.D_TIME.CAL_YYYYMM
    -- bg4643wj2d3xn
    =====================================
    Elapsed: 00:39:35.08
    Execution Plan
    Plan hash value: 2317670688
    | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
    | 0 | SELECT STATEMENT | | 9 | 666 | | 186K (1)| 00:43:36 | | |
    | 1 | HASH GROUP BY | | 9 | 666 | | 186K (1)| 00:43:36 | | |
    |* 2 | FILTER | | | | | | | | |
    |* 3 | HASH JOIN | | 557K| 39M| | 186K (1)| 00:43:35 | | |
    |* 4 | VIEW | index$_join$_006 | 1925 | 19250 | | 16 (7)| 00:00:01 | | |
    |* 5 | HASH JOIN | | | | | | | | |
    |* 6 | INDEX RANGE SCAN | D_TIME_CALYYYYMM_IDX2 | 1925 | 19250 | | 5 (20)| 00:00:01 | | |
    | 7 | INDEX FAST FULL SCAN | D_TIME_TIME_KEY_PK | 1925 | 19250 | | 14 (0)| 00:00:01 | | |
    |* 8 | HASH JOIN | | 557K| 34M| 32M| 186K (1)| 00:43:34 | | |
    | 9 | PARTITION RANGE ALL | | 557K| 26M| | 131K (1)| 00:30:46 | 1 | 133 |
    | 10 | TABLE ACCESS BY LOCAL INDEX ROWID| F_JOB_OIL_COST | 557K| 26M| | 131K (1)| 00:30:46 | 1 | 133 |
    | 11 | BITMAP CONVERSION TO ROWIDS | | | | | | | | |
    | 12 | BITMAP AND | | | | | | | | |
    | 13 | BITMAP MERGE | | | | | | | | |
    | 14 | BITMAP KEY ITERATION | | | | | | | | |
    | 15 | BUFFER SORT | | | | | | | | |
    |* 16 | VIEW | index$_join$_179 | 2 | 20 | | 2 (50)| 00:00:01 | | |
    |* 17 | HASH JOIN | | | | | | | | |
    | 18 | INLIST ITERATOR | | | | | | | | |
    |* 19 | INDEX UNIQUE SCAN | D_CAPSTS_ETL_IDX | 2 | 20 | | 0 (0)| 00:00:01 | | |
    | 20 | INDEX FAST FULL SCAN | D_VEHICLE_CAP_STATUS_PK | 2 | 20 | | 1 (0)| 00:00:01 | | |
    |* 21 | BITMAP INDEX RANGE SCAN | BIMAP_JOBOIL_COST_VEH_CAP_KY | | | | | | 1 | 133 |
    | 22 | BITMAP MERGE | | | | | | | | |
    | 23 | BITMAP KEY ITERATION | | | | | | | | |
    | 24 | BUFFER SORT | | | | | | | | |
    |* 25 | TABLE ACCESS FULL | D_TIME | 1925 | 51975 | | 19 (6)| 00:00:01 | | |
    |* 26 | BITMAP INDEX RANGE SCAN | BIMAP_JOBOIL_CST_RO_ACC_MTH_KY | | | | | | 1 | 133 |
    | 27 | BITMAP MERGE | | | | | | | | |
    | 28 | BITMAP KEY ITERATION | | | | | | | | |
    | 29 | BUFFER SORT | | | | | | | | |
    |* 30 | TABLE ACCESS FULL | D_ACCOUNT_CODE | 11 | 165 | | 4 (0)| 00:00:01 | | |
    |* 31 | BITMAP INDEX RANGE SCAN | BIMAP_JOBOIL_COST_ACCT_CODE_KY | | | | | | 1 | 133 |
    | 32 | BITMAP MERGE | | | | | | | | |
    | 33 | BITMAP KEY ITERATION | | | | | | | | |
    | 34 | BUFFER SORT | | | | | | | | |
    |* 35 | VIEW | index$_join$_172 | 3136 | 28224 | | 19 (6)| 00:00:01 | | |
    |* 36 | HASH JOIN | | | | | | | | |
    | 37 | INLIST ITERATOR | | | | | | | | |
    |* 38 | INDEX RANGE SCAN | D_LOCNMST_ETL_IDX | 3136 | 28224 | | 12 (17)| 00:00:01 | | |
    | 39 | INDEX FAST FULL SCAN | LOCATION_MASTER_KEY_PK | 3136 | 28224 | | 10 (0)| 00:00:01 | | |
    |* 40 | BITMAP INDEX RANGE SCAN | BIMAP_JOBOIL_COST_CHRG_LOCN_KY | | | | | | 1 | 133 |
    |* 41 | TABLE ACCESS FULL | D_UNIT_MASTER | 1790K| 23M| | 51484 (2)| 00:12:01 | | |
    |* 42 | TABLE ACCESS BY INDEX ROWID | S_LOCATION | 1 | 23 | | 12 (0)| 00:00:01 | | |
    |* 43 | INDEX RANGE SCAN | S_LOCN_SSOID_IDX | 14 | | | 1 (0)| 00:00:01 | | |
    Predicate Information (identified by operation id):
    2 - filter( EXISTS (SELECT 0 FROM "PTL_EDW"."S_LOCATION" "S_LOCATION" WHERE "S_LOCATION"."SSOID"='600028988' AND
    DECODE("S_LOCATION"."LOCATION_MASTER_KEY",(-99999),:B1,"S_LOCATION"."LOCATION_MASTER_KEY")=:B2))
    3 - access("F_JOB_OIL_COST"."RO_ACCOUNTING_MONTH_KEY"="D_TIME"."TIME_KEY")
    4 - filter("D_TIME"."CAL_YYYYMM">=200601 AND "D_TIME"."CAL_YYYYMM"<=201104)
    5 - access(ROWID=ROWID)
    6 - access("D_TIME"."CAL_YYYYMM">=200601 AND "D_TIME"."CAL_YYYYMM"<=201104)
    8 - access("F_JOB_OIL_COST"."UNIT_MASTER_KEY"="D_UNIT_MASTER"."UNIT_MASTER_KEY")
    16 - filter("D_VEHICLE_CAP_STATUS"."VEHICLE_CAP_STATUS"='ACCRUED' OR "D_VEHICLE_CAP_STATUS"."VEHICLE_CAP_STATUS"='ACTIVE')
    17 - access(ROWID=ROWID)
    19 - access("D_VEHICLE_CAP_STATUS"."VEHICLE_CAP_STATUS"='ACCRUED' OR "D_VEHICLE_CAP_STATUS"."VEHICLE_CAP_STATUS"='ACTIVE')
    21 - access("F_JOB_OIL_COST"."VEHICLE_CAP_STATUS_KEY"="D_VEHICLE_CAP_STATUS"."VEHICLE_CAP_STATUS_KEY")
    25 - filter("D_TIME"."CAL_YYYYMM">=200601 AND "D_TIME"."CAL_YYYYMM"<=201104)
    26 - access("F_JOB_OIL_COST"."RO_ACCOUNTING_MONTH_KEY"="D_TIME"."TIME_KEY")
    30 - filter("D_ACCOUNT_CODE"."ACCOUNT_CODE_GROUP1"='COMMERCIAL RENTAL' OR "D_ACCOUNT_CODE"."ACCOUNT_CODE_GROUP1"='CONTRACT MAINTENANCE
    - GUAR' OR "D_ACCOUNT_CODE"."ACCOUNT_CODE_GROUP1"='CONTRACT MAINTENANCE - OTHER' OR "D_ACCOUNT_CODE"."ACCOUNT_CODE_GROUP1"='CONTRACT
    MAINTENANCE - PEG' OR "D_ACCOUNT_CODE"."ACCOUNT_CODE_GROUP1"='LEASE' OR "D_ACCOUNT_CODE"."ACCOUNT_CODE_GROUP1"='TRAILER PLUS')
    31 - access("F_JOB_OIL_COST"."ACCOUNT_CODE_KEY"="D_ACCOUNT_CODE"."ACCOUNT_CODE_KEY")
    35 - filter("D_LOCATION_DOMICILE"."CORP_CD"='2000' OR "D_LOCATION_DOMICILE"."CORP_CD"='HPTL')
    36 - access(ROWID=ROWID)
    38 - access("D_LOCATION_DOMICILE"."CORP_CD"='2000' OR "D_LOCATION_DOMICILE"."CORP_CD"='HPTL')
    40 - access("F_JOB_OIL_COST"."CHARGING_LOCATION_KEY"="D_LOCATION_DOMICILE"."LOCATION_MASTER_KEY")
    41 - filter("D_UNIT_MASTER"."CONTRACT_GROUP"='P' AND ("D_UNIT_MASTER"."UNIT_CATEGORY"='TRACTOR' OR
    "D_UNIT_MASTER"."UNIT_CATEGORY"='TRAILER' OR "D_UNIT_MASTER"."UNIT_CATEGORY"='TRUCK'))
    42 - filter(DECODE("S_LOCATION"."LOCATION_MASTER_KEY",(-99999),:B1,"S_LOCATION"."LOCATION_MASTER_KEY")=:B2)
    43 - access("S_LOCATION"."SSOID"='600028988')
    Note
    - star transformation used for this statement
    Statistics
    3034 recursive calls
    0 db block gets
    28519518 consistent gets
    1075291 physical reads
    0 redo size
    2519 bytes sent via SQL*Net to client
    567 bytes received via SQL*Net from client
    6 SQL*Net roundtrips to/from client
    4 sorts (memory)
    0 sorts (disk)
    64 rows processed
    Partition is range on YYYYMM(numeric format)

  • Hash partitions+pruning+star transformation

    Hi there,
    We are considering partitioning our fact table on product_id (hash) range and list not suitable for us, most queries by product.
    Couple of questions
    1) does oracle create the hash partitions automaticall, if say hash by quantity what happens if later decide need more partitions - keen to keep maintenance to minimum
    2) Will partition pruning work
    simplified structure of fact table
    sales_qty
    product_id
    customer_id
    day_id (date of sale)
    simple query
    select sum(sale_qty)
    from sales, products, customers
    where sales.product_id = product.product_id
    and sales.customer_id = customer.customer_id
    and product.creation_week between 200901 and 200952
    all id's in the fact table are surrogate id's and are simply the dimesnion keys of the realetd dimensions, therefore users won't query omn these columns directly.
    If we hash partition on product_id and database parameter star_transformation enabled will this give us query performance benefits (i.e. partition pruning).
    Many Thanks

    Hi there,
    We are considering partitioning our fact table on product_id (hash) range and list not suitable for us, most queries by product.
    Couple of questions
    1) does oracle create the hash partitions automaticall, if say hash by quantity what happens if later decide need more partitions - keen to keep maintenance to minimum
    2) Will partition pruning work
    simplified structure of fact table
    sales_qty
    product_id
    customer_id
    day_id (date of sale)
    simple query
    select sum(sale_qty)
    from sales, products, customers
    where sales.product_id = product.product_id
    and sales.customer_id = customer.customer_id
    and product.creation_week between 200901 and 200952
    all id's in the fact table are surrogate id's and are simply the dimesnion keys of the realetd dimensions, therefore users won't query omn these columns directly.
    If we hash partition on product_id and database parameter star_transformation enabled will this give us query performance benefits (i.e. partition pruning).
    Many Thanks

  • Partition pruning question

    Oracle Version: 11.2.0.2
    OS platform : Solaris 10
    From EXPLAIN PLAN output (or any other method) of an SQL how can we tell that Partition pruning is not happening?
    What can be done so that optimizer will look at only the relevant partition(not the entire table) for records it is looking for ?

    What can be done if the optimizer seem to scan full tabe or lots of partitions instead of the relevant partition ?On partitioned tables there are two statistics: GLOBAL and LOCAL, if when we take the statistics we provide one partition (using the PARTNAME parameter) the global statistics will be also collected.
    The GRANULARITY parameter will allow you to decide the level of stats to be taken, GLOBAL as a whole object, PARTITION or SUBPARTITION.
    Options for the GRANULARITY parameter:
    'ALL' – gathers all (subpartition, partition, and global) statistics
    'AUTO'- determines the granularity based on the partitioning type. This is the default value.
    'DEFAULT' – gathers global and partition-level statistics. This option is obsolete, and while currently supported, it is included in the documentation for legacy reasons only. You should use the ‘GLOBAL AND PARTITION‘ for this functionality. Note that the default value is now ‘AUTO‘.
    'GLOBAL' – gathers global statistics
    ‘GLOBAL AND PARTITION‘ – gathers the global and partition level statistics. No subpartition level statistics are gathered even if it is a composite partitioned object.
    'PARTITION ‘- gathers partition-level statistics
    'SUBPARTITION' – gathers subpartition-level statistics.
    NOTE: Global statistics will not collect individual statistics for partitions and subpartitions.
    If we choose PARTITION or SUBPARTITION the stats will be taken in a fraction of the time, but there is a price for this speed, the GLOBAL stats for the whole table as an object will be missing, therefore only the queries that are using the partition key will have the stats.
    Conclusion : If you can afford to take GLOBAL stats then do it, you will have complete statistics for all your database, just set the GRANULARITY parameter to AUTO, this will also avoid stats problems when queries do not specify the partition key.
    Aggregated stats have worked out very well for me, but that might not be the case on all databases.
    So, just keep statistics updated and believe upon Optimizer, because when we are providing the correct and updated statistics, now optimizer will do best for us for sure.
    Regards
    Girish Sharma

  • 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

  • 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 in the partition_wise join

    Given tables table1 partitioned by hash on client_id column, and another table2 equipartitioned (hash on client_id column) I want to get both tables joined, but read the data partition by partition (in serial or from multiple client sessions). How to do this?
    select * from table1 T1, table2 T2
    where t1.client_id = t2.client_id
    The query above works fine - it DOES partition_wise join, but i cant use it since huge amount of rows it returns. Id like to use
    select *
    from table1 partition (P1) T1 ,
    table2 T2
    where t1.client_id = t2.client_id
    But in this case Oracle does not prune all Table2 partitions - it makes join between 1st partition of Table1 and all partitions of Table2. First question is why?
    I can fix it by pointing table2 partition too, then second question is - how can I be sure that all corresponding partitions with the same order number (given uniform partitioning for several tables) contain same keys?

    Using composite changes nothing. I've realized the problem - partition pruning is performed basing on "where" clause content. So, using "select from partition"
    does not affect a joined table. Probably, creating "partition_id" column filled with
    custom hash would solve the problem.

  • Partition Pruning vs Partition-Wise Join

    Hi,
    I am not sure if this is the right place for this question, but here it goes.
    I am in a situation where in the begining I have to join two big tables without any where clauses. It is pretty much a Caretsian Product where a criteria meets (Internal Code), but I have to join all rows. (Seems like a good place for Partition-Wise Join).
    Later I only need to update certain rows based on a key value (Customer ID, Region ID). (Good candidate for Partition Pruning).
    What would be the best option. Is there a way to use both?
    Assume that following:
    Table 1 has the structure of
    Customer ID
    Internal Code
    Other Data
    There are about 1000 Customer ID. Each Customer ID has 1000 Internal Codes.
    Table 2 has the structure of
    Region ID
    Internal Code
    Other Data
    There are about 5000 Region ID. Each Region ID has 1000 Internal Codes(same as Table 1).
    I am currently thinking of doing a HASH PARTITION (8 partitions) on Customer ID for Table 1 and HASH PARTITION (8 partitions) on Region ID for Table 2.
    The initial insert will take a long time, but when I go to update the joined data based on specific Customer ID, or Region ID atleast from one Table only one Partition will be used.
    I would sincerely appreciate some advice from the gurus.
    Thanks...

    Hi,
    I still don't understand what it is that you are trying to do.
    Would it be possible for you to create a silly example with just a few rows
    to show us what it is that you are trying to accomplish?
    Then we can help you solve whatever problem it is that you are having.
    create table t1(
       customer_id   number       not null
      ,internal_code varchar2(20) not null
      ,<other_columns>
      ,constraint t1_pk primary key(customer_id, internal_code)
    create table t2(
       region_id number not null
      ,internal_code varchar2(20) not null
      ,<other_columns>
      ,constraint t2_pk primary key(region_id, internal_code)
    insert into t1(customer_id, internal_code, ...) values(...);
    insert into t1(customer_id, internal_code, ...) values(...);
    insert into t2(region_id, internal_code, ...) values(...);
    insert into t2(region_id, internal_code, ...) values(...);
    select <the rating calculation>
       from t1 join t2 using(internal_code);

  • Partition pruning not working for partitioned table joins

    Hi,
    We are joining  4 partitioned tables on partition column & other key columns. And we are filtering the driving table on partition key. But explain plan is showing that all tables except the driving table are not partition pruning and scanning all partitions.Is there any limitation that filter condition cannot be dynamic?
    Thanks a lot in advance.
    Here are the details...
    SELECT a.pay_prd_id,
                  a.a_id,
                  a.a_evnt_no
      FROM b,
                c,
                a,
                d
    WHERE  (    a.pay_prd_id = b.pay_prd_id ---partition range all
                AND a.a_evnt_no  = b.b_evnt_no
                AND a.a_id       = b.b_id
       AND (    a.pay_prd_id = c.pay_prd_id---partition range all
            AND a.a_evnt_no  = c.c_evnt_no
            AND a.a_id       = c.c_id
       AND (    a.pay_prd_id = d.pay_prd_id---partition range all
            AND a.a_evnt_no  = d.d_evnt_no
            AND a.a_id       = d.d_id
       AND (a.pay_prd_id =  ---partition range single
               CASE '201202'
                  WHEN 'YYYYMM'
                     THEN (SELECT min(pay_prd_id)
                                      FROM pay_prd
                                     WHERE pay_prd_stat_cd = 2)
                  ELSE TO_NUMBER ('201202', '999999')
               END
    DDLs.
    create table pay_prd
    pay_prd_id number(6),
    pay_prd_stat_cd integer,
    pay_prd_stat_desc varchar2(20),
    a_last_upd_dt DATE
    insert into pay_prd
    select 201202,2,'OPEN',sysdate from dual
    union all
    select 201201,1,'CLOSE',sysdate from dual
    union all
    select 201112,1,'CLOSE',sysdate from dual
    union all
    select 201111,1,'CLOSE',sysdate from dual
    union all
    select 201110,1,'CLOSE',sysdate from dual
    union all
    select 201109,1,'CLOSE',sysdate from dual
    CREATE TABLE A
    (PAY_PRD_ID    NUMBER(6) NOT NULL,
    A_ID        NUMBER(9) NOT NULL,
    A_EVNT_NO    NUMBER(3) NOT NULL,
    A_DAYS        NUMBER(3),
    A_LAST_UPD_DT    DATE
    PARTITION BY RANGE (PAY_PRD_ID)
    INTERVAL( 1)
      PARTITION A_0001 VALUES LESS THAN (201504)
    ENABLE ROW MOVEMENT;
    ALTER TABLE A ADD CONSTRAINT A_PK PRIMARY KEY (PAY_PRD_ID,A_ID,A_EVNT_NO) USING INDEX LOCAL;
    insert into a
    select 201202,1111,1,65,sysdate from dual
    union all
    select 201202,1111,2,75,sysdate from dual
    union all
    select 201202,1111,3,85,sysdate from dual
    union all
    select 201202,1111,4,95,sysdate from dual
    CREATE TABLE B
    (PAY_PRD_ID    NUMBER(6) NOT NULL,
    B_ID        NUMBER(9) NOT NULL,
    B_EVNT_NO    NUMBER(3) NOT NULL,
    B_DAYS        NUMBER(3),
    B_LAST_UPD_DT    DATE
    PARTITION BY RANGE (PAY_PRD_ID)
    INTERVAL( 1)
      PARTITION B_0001 VALUES LESS THAN (201504)
    ENABLE ROW MOVEMENT;
    ALTER TABLE B ADD CONSTRAINT B_PK PRIMARY KEY (PAY_PRD_ID,B_ID,B_EVNT_NO) USING INDEX LOCAL;
    insert into b
    select 201202,1111,1,15,sysdate from dual
    union all
    select 201202,1111,2,25,sysdate from dual
    union all
    select 201202,1111,3,35,sysdate from dual
    union all
    select 201202,1111,4,45,sysdate from dual
    CREATE TABLE C
    (PAY_PRD_ID    NUMBER(6) NOT NULL,
    C_ID        NUMBER(9) NOT NULL,
    C_EVNT_NO    NUMBER(3) NOT NULL,
    C_DAYS        NUMBER(3),
    C_LAST_UPD_DT    DATE
    PARTITION BY RANGE (PAY_PRD_ID)
    INTERVAL( 1)
      PARTITION C_0001 VALUES LESS THAN (201504)
    ENABLE ROW MOVEMENT;
    ALTER TABLE C ADD CONSTRAINT C_PK PRIMARY KEY (PAY_PRD_ID,C_ID,C_EVNT_NO) USING INDEX LOCAL;
    insert into c
    select 201202,1111,1,33,sysdate from dual
    union all
    select 201202,1111,2,44,sysdate from dual
    union all
    select 201202,1111,3,55,sysdate from dual
    union all
    select 201202,1111,4,66,sysdate from dual
    CREATE TABLE D
    (PAY_PRD_ID    NUMBER(6) NOT NULL,
    D_ID        NUMBER(9) NOT NULL,
    D_EVNT_NO    NUMBER(3) NOT NULL,
    D_DAYS        NUMBER(3),
    D_LAST_UPD_DT    DATE
    PARTITION BY RANGE (PAY_PRD_ID)
    INTERVAL( 1)
      PARTITION D_0001 VALUES LESS THAN (201504)
    ENABLE ROW MOVEMENT;
    ALTER TABLE D ADD CONSTRAINT D_PK PRIMARY KEY (PAY_PRD_ID,D_ID,D_EVNT_NO) USING INDEX LOCAL;
    insert into c
    select 201202,1111,1,33,sysdate from dual
    union all
    select 201202,1111,2,44,sysdate from dual
    union all
    select 201202,1111,3,55,sysdate from dual
    union all
    select 201202,1111,4,66,sysdate from dual

    Below query generated from Business Objects and submitted to Database (the case statement is generated by BO). Cant we use Case/Subquery/Decode etc for the partitioned column? We are assuming that  the case causing the issue to not to dynamic partition elimination on the other joined partitioned tables (TAB_B_RPT, TAB_C_RPT).
    SELECT TAB_D_RPT.acvy_amt,
           TAB_A_RPT.itnt_typ_desc,
           TAB_A_RPT.ls_typ_desc,
           TAB_A_RPT.evnt_no,
           TAB_C_RPT.pay_prd_id,
           TAB_B_RPT.id,
           TAB_A_RPT.to_mdfy,
           TAB_A_RPT.stat_desc
      FROM TAB_D_RPT,
           TAB_C_RPT fee_rpt,
           TAB_C_RPT,
           TAB_A_RPT,
           TAB_B_RPT
    WHERE (TAB_B_RPT.id = TAB_A_RPT.id)
       AND (    TAB_A_RPT.pay_prd_id = TAB_D_RPT.pay_prd_id -- expecting Partition Range Single, but doing Partition Range ALL
            AND TAB_A_RPT.evnt_no    = TAB_D_RPT.evnt_no
            AND TAB_A_RPT.id         = TAB_D_RPT.id
       AND (    TAB_A_RPT.pay_prd_id = TAB_C_RPT.pay_prd_id -- expecting Partition Range Single, but doing Partition Range ALL
            AND TAB_A_RPT.evnt_no    = TAB_C_RPT.evnt_no
            AND TAB_A_RPT.id         = TAB_C_RPT.id
       AND (    TAB_A_RPT.pay_prd_id = fee_rpt.pay_prd_id -- expecting Partition Range Single
            AND TAB_A_RPT.evnt_no    = fee_rpt.evnt_no
            AND TAB_A_RPT.id         = fee_rpt.id
       AND (TAB_A_RPT.rwnd_ind = 'N')
       AND (TAB_A_RPT.pay_prd_id =
               CASE '201202'
                  WHEN 'YYYYMM'
                     THEN (SELECT DISTINCT pay_prd.pay_prd_id
                                      FROM pay_prd
                                     WHERE pay_prd.stat_cd = 2)
                  ELSE TO_NUMBER ('201202', '999999')
               END
    And its explain plan is...
    Plan
    SELECT STATEMENT ALL_ROWS Cost: 79 K Bytes: 641 M Cardinality: 3 M
    18 HASH JOIN Cost: 79 K Bytes: 641 M Cardinality: 3 M
    3 PART JOIN FILTER CREATE SYS.:BF0000 Cost: 7 K Bytes: 72 M Cardinality: 3 M
    2 PARTITION RANGE ALL Cost: 7 K Bytes: 72 M Cardinality: 3 M Partition #: 3 Partitions accessed #1 - #1048575
    1 TABLE ACCESS FULL TABLE TAB_D_RPT Cost: 7 K Bytes: 72 M Cardinality: 3 M Partition #: 3 Partitions accessed #1 - #1048575
    17 HASH JOIN Cost: 57 K Bytes: 182 M Cardinality: 874 K
    14 PART JOIN FILTER CREATE SYS.:BF0001 Cost: 38 K Bytes: 87 M Cardinality: 914 K
    13 HASH JOIN Cost: 38 K Bytes: 87 M Cardinality: 914 K
    6 PART JOIN FILTER CREATE SYS.:BF0002 Cost: 8 K Bytes: 17 M Cardinality: 939 K
    5 PARTITION RANGE ALL Cost: 8 K Bytes: 17 M Cardinality: 939 K Partition #: 9 Partitions accessed #1 - #1048575
    4 TABLE ACCESS FULL TABLE TAB_C_RPT Cost: 8 K Bytes: 17 M Cardinality: 939 K Partition #: 9 Partitions accessed #1 - #1048575
    12 HASH JOIN Cost: 24 K Bytes: 74 M Cardinality: 957 K
    7 INDEX FAST FULL SCAN INDEX (UNIQUE) TAB_B_RPT_PK Cost: 675 Bytes: 10 M Cardinality: 941 K
    11 PARTITION RANGE SINGLE Cost: 18 K Bytes: 65 M Cardinality: 970 K Partition #: 13 Partitions accessed #KEY(AP)
    10 TABLE ACCESS FULL TABLE TAB_A_RPT Cost: 18 K Bytes: 65 M Cardinality: 970 K Partition #: 13 Partitions accessed #KEY(AP)
    9 HASH UNIQUE Cost: 4 Bytes: 14 Cardinality: 2
    8 TABLE ACCESS FULL TABLE PAY_PRD Cost: 3 Bytes: 14 Cardinality: 2
    16 PARTITION RANGE JOIN-FILTER Cost: 8 K Bytes: 106 M Cardinality: 939 K Partition #: 17 Partitions accessed #:BF0001
    15 TABLE ACCESS FULL TABLE TAB_C_RPT Cost: 8 K Bytes: 106 M Cardinality: 939 K Partition #: 17 Partitions accessed #:BF0001
    Thanks Again.

  • Partition pruning

    Hi,
    We use Oracle 11.2.0.3 and are being aksed to considering implementing partitioning as follows:
    We will have a lrage fact table -several billion records
    structure is
    product_id,
    various other dimension _keys
    and the measures.
    It is a star schema and all the ids are surrogate keys which are fks to the dimension tables.
    Irt is being suggested to add extra column to the fact table - partitioning date and range-partition the sales fact and product dimenision by this new column and also the product dimension such that the join between the central sales atr becomes
    where sales.product_id = product.dimension_key
    and sales.partitiong_date = product.partioning_date
    On the basis that partition-pruning will occur.
    I'm no expert on partitioning but I'm not sure this will give th desired affect of partition-pruning as the partitioning-date column will not be referred to directly
    e. no queries wil say and partitiong_date = '27-OCT-2012'
    Will partition-pruning occure simply n fact fact table and dimesnion table now would have this extra join on them.
    Any advice would be great before we go down this path espeacilly if it is a dead-end in tersm of no material benefit or worse woudl make queries very slow.
    Thanks

    >
    Will partition-pruning occure simply n fact fact table and dimesnion table now would have this extra join on them.
    >
    No.
    >
    We use Oracle 11.2.0.3 and are being aksed to considering implementing partitioning
    >
    Why? You don't partition just because you can. You need a reason. Ask them why they want you to partition. What are you trying to achieve?
    >
    Do you have any suggestions how best to partition a fact table which only has surrogate keys and measures. No genuine date column as such like sales_date.
    >
    Not without knowing what goal you are trying to achieve. If you are trying to improve performance then you need to provide a sample query that you want to improve.
    If there is no partition pruning then performance will only be improved if the queries execute in PARALLEL.
    For partition pruning to occur there must be at least one filter predicate in the query that allows Oracle to determine which partitions the required data is in. .
    Partitioning on product_id will only allow pruning if the queries use product_id as a predicate. If it is a surrogate key and not a real value then users can't use it directly and so queries would likely only get the actual product_id value by using a lookup table from a product dimension table.
    So a lot more information is needed in order to provide any specific suggestions.
    1. What is the initial size of the table to be partitioned?
    2. How much DML activity (INSERTs, DELETEs, UPDATEs) is expected?
    3. Is the DML in #2 daily, weekly, monthly?
    4. Is there a need to remove old data periodically? For example keep three years online and each month remove the oldest month?
    5. What are the typical columns being filtered on when users query the data?
    6. Is the an OLTP system or datawarehouse?

  • 11g new feature "Partition pruning based on bloom filtering" is what?

    While idly reading the Oracle 11g Database New Features I stumbled upon the following - BEGIN QUOTE:
    1.11.1.2 Enhanced Partition Pruning Capabilities
    Partition pruning now uses bloom filtering instead of subquery pruning. While subquery pruning was activated on a cost-based decision and consumed internal (recursive) resources, pruning based on bloom filtering is activated all the time without consuming additional resources.
    END QUOTE
    I haven't found any other references to bloom filtering in the manuals, and very few via google and MetaLink. So I am left wondering what the above paragraph actually means?
    Best regards,
    Hans Henrik Krohn

    Hi Hans
    The problem of subquery pruning is that part of the SQL statement is executed twice. Therefore, a cost-based decision is necessary to decide if it makes to do it or not...
    To avoid this double execution they introduced join-filter pruning (which takes advantage of a bloom filter). Since this new method has a very small overhead, it makes always sense to use it if pruning can be used. With it you will see execution plans like the following one.
    | Operation                           | Name    | Pstart| Pstop |
    | HASH JOIN                           |         |       |       |
    |  PART JOIN FILTER CREATE            | :BF0000 |       |       |
    |   TABLE ACCESS BY GLOBAL INDEX ROWID| T       | ROWID | ROWID |
    |    INDEX UNIQUE SCAN                | T_PK    |       |       |
    |  PARTITION RANGE JOIN-FILTER        |         |:BF0000|:BF0000|
    |   TABLE ACCESS FULL                 | T       |:BF0000|:BF0000|
    -----------------------------------------------------------------HTH
    Chris

  • DB partition Pruning

    Hello, Someone told me that HANA db partition will not prune and the advantage of using Semantic Partition over DB partition is pruning. Does it correct? Thanks, Amir

    This is not correct.
    SAP HANA does support partition pruning on DB level.
    Using SPOs in SAP BW on HANA however provides a lot of additional benefits that can only be leveraged in the application/BW layer.
    Thus, the recommendation to use SPOs is valid.

Maybe you are looking for