Search code examples
sqlplsqldatabase-partitioning

select max of a column using range partition


I have a Table which is range partitioned on numeric(parameterinstanceid) value. I want to select max+1 value of the same column .i have global non-partition index on parameterinstanceid.

select /*+ parallel(a,32,8) */ max(parameterinstanceid) +1 from parameterinstance a;

On checking the explain plan i see that it is doing a INDEX FULL SCAN (MIN/MAX) on the table. i want to do it by checking in max partition first,if it doesnt contain any data ,then next partition ,in desc order .i can write a procedure to do that ,but i want to know if there is a simple query for it. http://www.oramoss.com/blog/2009/06/no-pruning-for-minmax-of-partition-key.html ..it seems that it is a unsolved issue.

EDIT :

The partition names are PI_P01,PI_P02,...PI_P10,PI_PMAXVALUE

explain plan is:

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2808487136

-----------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |       |     1 |     8 |    34   (0)| 00:00:01 |       |       |
|   1 |  SORT AGGREGATE             |       |     1 |     8 |            |          |       |       |
|   2 |   PARTITION RANGE ALL       |       |     1 |     8 |    34   (0)| 00:00:01 |     1 |    11 |
|   3 |    INDEX FULL SCAN (MIN/MAX)| PI_PK |     1 |     8 |    34   (0)| 00:00:01 |     1 |    11 |
-----------------------------------------------------------------------------------------------------

and table struct:

 Name                           Null?    Type
 ------------------------------ -------- -----------------
 PARAMETERINSTANCEID            NOT NULL NUMBER
 PARAMINSTANCE2PARAMSETVERSION  NOT NULL NUMBER
 PARAMINSTANCE2PARAMDEFINITION  NOT NULL NUMBER
 PARAMINSTANCE2PARENTPARAM               NUMBER
 SEQUENCE                                NUMBER
 X_CTCV_CONV_ID                          VARCHAR2(50 CHAR)
 X_CONV_RUN_NO                           NUMBER

and the indexes on the table :

    INDEX_NAME                     POSITION COLUMN_NAME 
------------------------------ -------- -----------------------------
PI_UK                                 1 PARAMINSTANCE2PARAMSETVERSION
PI_UK                                 2 PARAMINSTANCE2PARAMDEFINITION
PI_PK                                 1 PARAMETERINSTANCEID            
PI_PAD_FK_I                           1 PARAMINSTANCE2PARAMDEFINITION
PI_PI_FK_I                            1 PARAMINSTANCE2PARENTPARAM      

Solution

  • If you have a global index on the partition key, you should get a plan like this:

    ----------------------------------------------------------------------------
    | Id  | Operation                  | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT           |     1 |     9 |     2   (0)| 00:00:01 |
    |   1 |  SORT AGGREGATE            |     1 |     9 |            |          |
    |   2 |   INDEX FULL SCAN (MIN/MAX)|     1 |     9 |     2   (0)| 00:00:01 |
    ----------------------------------------------------------------------------
    

    Here the MIN/MAX is very significant, it means that Oracle will stop at the first entry, bypassing the partition table.

    The link you have provided is different since the partition key is not indexed (hence it produces a FULL TABLE SCAN instead of an INDEX FULL SCAN.

    If you have no index on the partition key, it seems that going for a TOP-N query as suggested by Jonathan Lewis may do exactly what you want. Here is the plan I get with the table test as in the example in your link:

    explain plan for 
    select * from (select col_date_part_key 
                     from test 
                    order by col_date_part_key desc) 
     where rownum = 1
    
    -------------------------------------------------------------------------
    | Id  | Operation                | Name | Rows  | Bytes | Pstart| Pstop |
    -------------------------------------------------------------------------
    |   0 | SELECT STATEMENT         |      |     1 |     9 |       |       |
    |*  1 |  COUNT STOPKEY           |      |       |       |       |       |
    |   2 |   PARTITION RANGE ALL    |      |     1 |     9 |    12 |     1 |
    |   3 |    VIEW                  |      |     1 |     9 |       |       |
    |*  4 |     SORT ORDER BY STOPKEY|      |     1 |     9 |       |       |
    |   5 |      TABLE ACCESS FULL   | TEST |     1 |     9 |    12 |     1 |
    -------------------------------------------------------------------------
    

    As you can see Oracle will start with the last partition (Pstart=12) and will walk up to the first partition (Pstart=1) until it gets one row (Rows=1).


    Update

    I've run another test with a setup I hope is similar to yours and I find a different, more logical plan. Setup:

    create table parameterinstance  (
       PARAMETERINSTANCEID           NUMBER             NOT NULL,
       PARAMINSTANCE2PARAMSETVERSION NUMBER             NOT NULL,
       PARAMINSTANCE2PARAMDEFINITION NUMBER             NOT NULL,
       PARAMINSTANCE2PARENTPARAM     NUMBER                     ,
       SEQUENCE                      NUMBER                     ,
       X_CTCV_CONV_ID                VARCHAR2(50 CHAR)          ,
       X_CONV_RUN_NO                 NUMBER                     
    ) partition by range (PARAMETERINSTANCEID)
    (  partition p1 values less than (1000) storage (initial 64k),
       partition p2 values less than (2000) storage (initial 64k),
       partition p3 values less than (3000) storage (initial 64k),
       partition p4 values less than (4000) storage (initial 64k),
       partition p5 values less than (5000) storage (initial 64k),
       partition p6 values less than (6000) storage (initial 64k),
       partition p7 values less than (7000) storage (initial 64k),
       partition p8 values less than (8000) storage (initial 64k),
       partition p9 values less than (9000) storage (initial 64k),
       partition p10 values less than (maxvalue) storage (initial 64k)
    );
    
    CREATE UNIQUE INDEX PI_PK ON parameterinstance(PARAMETERINSTANCEID) local;
    
    insert into parameterinstance  
      (SELECT rownum, rownum, rownum, '', '', rpad('x', 50, 'x'), '' 
         from dual connect by level <= 1e4);
    

    On 11gR2 i get the following plan:

    -----------------------------------------------------------------------------
    | Id  | Operation                   | Name  | Rows  | Bytes | Pstart| Pstop |
    -----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |       |     1 |    13 |       |       |
    |   1 |  PARTITION RANGE ALL        |       |     1 |    13 |    10 |     1 |
    |   2 |   SORT AGGREGATE            |       |     1 |    13 |       |       |
    |   3 |    INDEX FULL SCAN (MIN/MAX)| PI_PK |     1 |    13 |    10 |     1 |
    -----------------------------------------------------------------------------
    

    Note that the partition are listed in the appropriate order (from 10 downwards to 1). The plan is different in 9iR2:

    -----------------------------------------------------------------------------
    | Id  | Operation                   | Name  | Rows  | Bytes | Pstart| Pstop |
    -----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT            |       |     1 |     4 |       |       |
    |   1 |  SORT AGGREGATE             |       |     1 |     4 |       |       |
    |   2 |   PARTITION RANGE ALL       |       |       |       |     1 |    10 |
    |   3 |    INDEX FULL SCAN (MIN/MAX)| PI_PK | 10000 | 40000 |     1 |    10 |
    -----------------------------------------------------------------------------
    

    So it seems that some optimization has taken place between 9i and 11g. Time for an upgrade?