Selecting both MIN and MAX From the Table is slower than expected

后端 未结 4 1567
忘掉有多难
忘掉有多难 2021-02-05 03:41

I have a table MYTABLE with a date column SDATE which is the primary key of the table and has a unique index on it.

When I run this query:

4条回答
  •  -上瘾入骨i
    2021-02-05 04:26

    I have to say that I do not see the same behaviour in 11.2

    If I set up a test case as follows and updated from 10k to 1m rows in response to Vincent's comment

    set linesize 130
    set pagesize 0
    create table mytable ( sdate date );
    
    Table created.
    
    insert into mytable
     select sysdate - level
       from dual
    connect by level <= 1000000;
    commit;
    
    1000000 rows created.
    
    
    Commit complete.
    
    alter table mytable add constraint pk_mytable primary key ( sdate ) using index;
    
    Table altered.
    
    begin
    dbms_stats.gather_table_stats( user, 'MYTABLE' 
                                 , estimate_percent => 100
                                 , cascade => true
                                   );
    end;
    /
    
    PL/SQL procedure successfully completed.
    

    Then, executing your queries I get almost identical looking explain plans (notice the different types of INDEX FULL SCAN)

    explain plan for select min(sdate) from mytable;
    
    Explained.
    
    select * from table(dbms_xplan.display);
    Plan hash value: 3877058912
    
    -----------------------------------------------------------------------------------------
    | Id  | Operation          | Name   | Rows  | Bytes | Cost (%CPU)| Time |
    -----------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT       |        |     1 |     8 |     1   (0)| 00:00:01 |
    |   1 |  SORT AGGREGATE        |        |     1 |     8 |        |      |
    |   2 |   INDEX FULL SCAN (MIN/MAX)| PK_MYTABLE |     1 |     8 |     1   (0)| 00:00:01 |
    -----------------------------------------------------------------------------------------
    
    9 rows selected.
    
    explain plan for select min(sdate), max(sdate) from mytable;
    
    Explained.
    
    select * from table(dbms_xplan.display);
    Plan hash value: 3812733167
    
    -------------------------------------------------------------------------------
    | Id  | Operation    | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
    -------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT |        |     1 |     8 |   252   (0)| 00:00:04 |
    |   1 |  SORT AGGREGATE  |        |     1 |     8 |        |          |
    |   2 |   INDEX FULL SCAN| PK_MYTABLE |  1000K|  7812K|   252   (0)| 00:00:04 |
    -------------------------------------------------------------------------------
    
    9 rows selected.
    

    To quote from a previous answer of mine:

    The two most common reasons for a query not using indexes are:

    1. It's quicker to do a full table scan.
    2. Poor statistics.

    Unless there's something you're not posting in the question my immediate answer would be that you have not collected statistics on this table, you haven't collected them with a high enough estimate percent or you've used analyze, which will not help the Cost Based Optimizer, unlike dbms_stats.gather_table_stats.

    To quote from the documentation on analyze:

    For the collection of most statistics, use the DBMS_STATS package, which lets you collect statistics in parallel, collect global statistics for partitioned objects, and fine tune your statistics collection in other ways. See Oracle Database PL/SQL Packages and Types Reference for more information on the DBMS_STATS package.

    Use the ANALYZE statement (rather than DBMS_STATS) for statistics collection not related to the cost-based optimizer:

提交回复
热议问题