联系:QQ(5163721)
标题:让“select min(xxx),max(xxx) from xxx”走索引
作者:Lunar©版权所有[文章允许转载,但必须以链接方式注明源地址,否则追究法律责任.]
首先,做一个测试表:
[oracle@lunar /]$ ss SQL*Plus: Release 11.2.0.3.0 Production on Sat Jun 7 21:29:52 2014 Copyright (c) 1982, 2011, Oracle. All rights reserved. Welcome Lunar's oracle world! Love you , baby ! Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production With the Partitioning and Real Application Testing options SYS@lunar>conn lunar/lunar Welcome Lunar's oracle world! Love you , baby ! Connected. LUNAR@lunar>create table lunar as select * from dba_extents; Table created. Elapsed: 00:00:04.61
在extent_id列上创建非唯一索引:
LUNAR@lunar>create index idx_lunar_extent_id on lunar(extent_id) ; Index created. Elapsed: 00:00:00.02 LUNAR@lunar>EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'LUNAR',TABNAME => 'LUNAR',DEGREE => 5, 2 CASCADE => TRUE,ESTIMATE_PERCENT => DBMS_STATS.AUTO_SAMPLE_SIZE); PL/SQL procedure successfully completed. Elapsed: 00:00:01.45
下面的语句没有走索引:
LUNAR@lunar>select min(extent_id),max(extent_id) from lunar;
MIN(EXTENT_ID) MAX(EXTENT_ID)
-------------- --------------
             0             61
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 291688323
----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |     3 |    16   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |       |     1 |     3 |            |          |
|   2 |   TABLE ACCESS FULL| LUNAR |  5223 | 15669 |    16   (0)| 00:00:01 |
----------------------------------------------------------------------------
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
         51  consistent gets
          0  physical reads
          0  redo size
        610  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
LUNAR@lunar>
手工指定IDX_LUNAR_EXTENT_ID时,也不走索引:
LUNAR@lunar>select /*+ index(lunar IDX_LUNAR_EXTENT_ID) */ min(extent_id),max(extent_id) from lunar;
MIN(EXTENT_ID) MAX(EXTENT_ID)
-------------- --------------
             0             61
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 291688323
----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |     3 |    16   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |       |     1 |     3 |            |          |
|   2 |   TABLE ACCESS FULL| LUNAR |  5223 | 15669 |    16   (0)| 00:00:01 |
----------------------------------------------------------------------------
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
         50  consistent gets
          0  physical reads
          0  redo size
        610  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
LUNAR@lunar>
指定该列为非空时,可以走索引(Oracle的索引不保存空值):
LUNAR@lunar>alter table lunar modify extent_id not null; Table altered. Elapsed: 00:00:00.24 LUNAR@lunar>
可以看到,无论是否使用hint都走索引了:
LUNAR@lunar>set autotrace on
LUNAR@lunar>select /*+ index(lunar IDX_LUNAR_EXTENT_ID) */ min(extent_id),max(extent_id) from lunar;
MIN(EXTENT_ID) MAX(EXTENT_ID)
-------------- --------------
             0             61
Elapsed: 00:00:00.00
Execution Plan
----------------------------------------------------------
Plan hash value: 1897601393
----------------------------------------------------------------------------------------
| Id  | Operation        | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                     |     1 |     3 |    11   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE  |                     |     1 |     3 |            |          |
|   2 |   INDEX FULL SCAN| IDX_LUNAR_EXTENT_ID |  5223 | 15669 |    11   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
注意: 使用hint时,走的是“INDEX FULL SCAN”
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
         11  consistent gets
          0  physical reads
          0  redo size
        610  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
LUNAR@lunar>select min(extent_id),max(extent_id) from lunar;
MIN(EXTENT_ID) MAX(EXTENT_ID)
-------------- --------------
             0             61
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 2695027278
---------------------------------------------------------------------------------------------
| Id  | Operation             | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                     |     1 |     3 |     4   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE       |                     |     1 |     3 |            |          |
|   2 |   INDEX FAST FULL SCAN| IDX_LUNAR_EXTENT_ID |  5223 | 15669 |     4   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
注意: 不使用hint时,走的是“INDEX FAST FULL SCAN”
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
         15  consistent gets
          0  physical reads
          0  redo size
        610  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
LUNAR@lunar>
再次验证,依然这个结果:
LUNAR@lunar>alter table lunar modify extent_id null;
Table altered.
Elapsed: 00:00:00.01
LUNAR@lunar>select min(extent_id),max(extent_id) from lunar;
MIN(EXTENT_ID) MAX(EXTENT_ID)
-------------- --------------
             0             61
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 291688323
----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |     3 |    16   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |       |     1 |     3 |            |          |
|   2 |   TABLE ACCESS FULL| LUNAR |  5223 | 15669 |    16   (0)| 00:00:01 |
----------------------------------------------------------------------------
Statistics
----------------------------------------------------------
         22  recursive calls
          0  db block gets
         75  consistent gets
          0  physical reads
          0  redo size
        610  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          6  sorts (memory)
          0  sorts (disk)
          1  rows processed
LUNAR@lunar>
单独查询最小值或者最大值时,也可以走索引,采用“INDEX FULL SCAN (MIN/MAX)”:
LUNAR@lunar>select min(extent_id) from lunar;
MIN(EXTENT_ID)
--------------
             0
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 4158629481
--------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                     |     1 |     3 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE            |                     |     1 |     3 |            |          |
|   2 |   INDEX FULL SCAN (MIN/MAX)| IDX_LUNAR_EXTENT_ID |     1 |     3 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          2  consistent gets
          0  physical reads
          0  redo size
        531  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
LUNAR@lunar>select max(extent_id) from lunar;
MAX(EXTENT_ID)
--------------
            61
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 4158629481
--------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                     |     1 |     3 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE            |                     |     1 |     3 |            |          |
|   2 |   INDEX FULL SCAN (MIN/MAX)| IDX_LUNAR_EXTENT_ID |     1 |     3 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          2  consistent gets
          0  physical reads
          0  redo size
        532  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
LUNAR@lunar>
假设,在不能修改表结构的情况下,怎么才能让“select min(extent_id),max(extent_id) from lunar”走索引呢?
参考了网上的一些建议,改写sql如下:
LUNAR@lunar>select 
  2  (select min(extent_id) from lunar) as min_extent_id,
  3  (select max(extent_id) from lunar) as max_extent_id
  4  from dual;
MIN_EXTENT_ID MAX_EXTENT_ID
------------- -------------
            0            61
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 778639039
--------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                     |     1 |       |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE            |                     |     1 |     3 |            |          |
|   2 |   INDEX FULL SCAN (MIN/MAX)| IDX_LUNAR_EXTENT_ID |     1 |     3 |     2   (0)| 00:00:01 |
|   3 |  SORT AGGREGATE            |                     |     1 |     3 |            |          |
|   4 |   INDEX FULL SCAN (MIN/MAX)| IDX_LUNAR_EXTENT_ID |     1 |     3 |     2   (0)| 00:00:01 |
|   5 |  FAST DUAL                 |                     |     1 |       |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          4  consistent gets
          0  physical reads
          0  redo size
        608  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
LUNAR@lunar>
											 
								 
 
 
 
 
