ITPub博客

首页 > 数据库 > Oracle > [20200303]降序索引疑问5.txt

[20200303]降序索引疑问5.txt

原创 Oracle 作者:lfree 时间:2020-03-04 09:03:55 0 删除 编辑

[20200303]降序索引疑问5.txt

--//昨天在优化sql语句时遇到一条sql语句.也是使用order by desc.
--//突然想起一些细节我自己以前没有注意到.必须认真考虑.
--//语句大致如下,换成*,不然太长了.
SELECT *  FROM (SELECT * FROM jcd this WHERE this.biaoshi =  :1  ORDER BY this.jcjs_time desc ) WHERE rownum <= :2;

> @ bind_cap abnnf6rh06s6c ''
SQL_ID        CHILD_NUMBER WAS NAME POSITION MAX_LENGTH LAST_CAPTURED       DATATYPE_STRING VALUE_STRING C30
------------- ------------ --- ---- -------- ---------- ------------------- --------------- ------------ --------------
abnnf6rh06s6c            0 YES :1          1         22 2017-11-01 15:32:04 NUMBER          57
                           YES :2          2         22 2017-11-01 15:32:04 NUMBER          200

--//疑问1:如果像上面的jcjs_time,如果jcjs_time 有NULL,NULL值是否优先输出.因为NULL不管什么number还是字符.在oracle的编码是0xFF.
--//疑问2:也是我最关注的,如果查询写成如下:
SELECT *  FROM (SELECT * FROM jcd this  ORDER BY this.jcjs_time desc ) WHERE rownum <= :2;
--//建立jcjs_time的普通索引和降序索引,在有NULL值的情况下,降序索引是否有效.

1.环境:
SCOTT@book> @ ver1
PORT_STRING                    VERSION        BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx            11.2.0.4.0     Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

create table t as select rownum id, trunc(dbms_random.value(1,100)) idx ,sysdate+rownum/1000-100 cr_date,rownum||lpad('x',100,'x') vc
from dual connect by level<=10e5-100;

insert into t select rownum+10e5-100 id, trunc(dbms_random.value(1,100)) idx ,NULL cr_date,rownum||lpad('x',100,'x') vc
from dual connect by level<=100;

commit ;

create index i_t_idx_cr_date on t(idx ,cr_date);
create index if_t_idx_cr_date on t(idx ,cr_date desc);
--//分析略.Method_Opt => 'FOR ALL COLUMNS SIZE 1 '

2.测试:
SCOTT@book> alter session set statistics_level = all;
Session altered.


SCOTT@book> SELECT *  FROM (SELECT * FROM t WHERE idx = 42 ORDER BY cr_date desc ) WHERE rownum <=5;
    ID IDX CR_DATE             VC
------ --- ------------------- ----------------------------------------------------------------------------------------------------------
999913  42                     13xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999884  42 2022-08-20 06:41:07 999884xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999698  42 2022-08-20 02:13:16 999698xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999543  42 2022-08-19 22:30:04 999543xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999382  42 2022-08-19 18:38:14 999382xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
--//可以发现NULL在第1个。

Plan hash value: 2332835607
--------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name            | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                 |      1 |        |       |     8 (100)|          |      5 |00:00:00.01 |       9 |
|*  1 |  COUNT STOPKEY                 |                 |      1 |        |       |            |          |      5 |00:00:00.01 |       9 |
|   2 |   VIEW                         |                 |      1 |      6 |   642 |     8   (0)| 00:00:01 |      5 |00:00:00.01 |       9 |
|   3 |    TABLE ACCESS BY INDEX ROWID | T               |      1 |  10101 |  1213K|     8   (0)| 00:00:01 |      5 |00:00:00.01 |       9 |
|*  4 |     INDEX RANGE SCAN DESCENDING| I_T_IDX_CR_DATE |      1 |      6 |       |     3   (0)| 00:00:01 |      5 |00:00:00.01 |       4 |
--------------------------------------------------------------------------------------------------------------------------------------------

SCOTT@book> SELECT *  FROM (SELECT /*+ index(t IF_T_IDX_CR_DATE )*/ * FROM t WHERE idx = 42 ORDER BY cr_date desc ) WHERE rownum <= 5;
    ID IDX CR_DATE             VC
------ --- ------------------- ----------------------------------------------------------------------------------------------------------
999913  42                     13xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999884  42 2022-08-20 06:41:07 999884xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999698  42 2022-08-20 02:13:16 999698xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999543  42 2022-08-19 22:30:04 999543xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999382  42 2022-08-19 18:38:14 999382xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Plan hash value: 313436017
--------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |      1 |        |       |     8 (100)|          |      5 |00:00:00.01 |       9 |
|*  1 |  COUNT STOPKEY                |                  |      1 |        |       |            |          |      5 |00:00:00.01 |       9 |
|   2 |   VIEW                        |                  |      1 |      6 |   642 |     8   (0)| 00:00:01 |      5 |00:00:00.01 |       9 |
|   3 |    TABLE ACCESS BY INDEX ROWID| T                |      1 |  10101 |  1213K|     8   (0)| 00:00:01 |      5 |00:00:00.01 |       9 |
|*  4 |     INDEX RANGE SCAN          | IF_T_IDX_CR_DATE |      1 |      6 |       |     3   (0)| 00:00:01 |      5 |00:00:00.01 |       4 |
--------------------------------------------------------------------------------------------------------------------------------------------
--//可以发现排序时NULL在最前面。

3.测试2
drop index i_t_idx_cr_date ;
drop index if_t_idx_cr_date;

create index i_t_cr_date on t(cr_date);
create index if_t_cr_date on t(cr_date desc);

--//分析略.Method_Opt => 'FOR ALL COLUMNS SIZE 1 '
SCOTT@book> select index_name,index_type,blevel,leaf_blocks,distinct_keys,num_rows from dba_indexes where owner=user and table_name='T';
INDEX_NAME                     INDEX_TYPE                      BLEVEL LEAF_BLOCKS DISTINCT_KEYS   NUM_ROWS
------------------------------ --------------------------- ---------- ----------- ------------- ----------
I_T_CR_DATE                    NORMAL                               2        2653        999900     999900
IF_T_CR_DATE                   FUNCTION-BASED NORMAL                2        2793        999901    1000000
--//从NUM_ROWS,DISTINCT_KEYS就可以看出降序索引是包含NULL的。

SCOTT@book> SELECT *  FROM (SELECT * FROM t  ORDER BY cr_date desc ) WHERE rownum <= 5;
    ID IDX CR_DATE             VC
------ --- ------------------- -----------------------------------------------------------------------------------------------------
999901  77                     1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999905   5                     5xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999904  47                     4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999903  51                     3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999902  19                     2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Plan hash value: 3299198703
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |      |      1 |        |       |       | 32529 (100)|          |      5 |00:00:00.68 |   17897 |  16777 |       |       |          |
|*  1 |  COUNT STOPKEY          |      |      1 |        |       |       |            |          |      5 |00:00:00.68 |   17897 |  16777 |       |       |          |
|   2 |   VIEW                  |      |      1 |   1000K|   102M|       | 32529   (1)| 00:06:31 |      5 |00:00:00.68 |   17897 |  16777 |       |       |          |
|*  3 |    SORT ORDER BY STOPKEY|      |      1 |   1000K|   117M|   130M| 32529   (1)| 00:06:31 |      5 |00:00:00.68 |   17897 |  16777 |  1683K|   633K| 1495K (0)|
|   4 |     TABLE ACCESS FULL   | T    |      1 |   1000K|   117M|       |  4933   (1)| 00:01:00 |   1000K|00:00:00.23 |   17897 |  16777 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------

--//执行计划选择全表扫描。并没有使用索引,使用普通索引可能不行,因为cr_date有NULL值。而降序索引包含NULL的,也不会使用。
--//加入提示看看。

SELECT *  FROM (SELECT /*+ index(t IF_T_CR_DATE )*/ * FROM t ORDER BY cr_date desc ) WHERE rownum <= 5;

Plan hash value: 3299198703
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |      |      1 |        |       |       | 32529 (100)|          |      5 |00:00:00.65 |   17897 |  16878 |       |       |          |
|*  1 |  COUNT STOPKEY          |      |      1 |        |       |       |            |          |      5 |00:00:00.65 |   17897 |  16878 |       |       |          |
|   2 |   VIEW                  |      |      1 |   1000K|   102M|       | 32529   (1)| 00:06:31 |      5 |00:00:00.65 |   17897 |  16878 |       |       |          |
|*  3 |    SORT ORDER BY STOPKEY|      |      1 |   1000K|   117M|   130M| 32529   (1)| 00:06:31 |      5 |00:00:00.65 |   17897 |  16878 |  1683K|   633K| 1495K (0)|
|   4 |     TABLE ACCESS FULL   | T    |      1 |   1000K|   117M|       |  4933   (1)| 00:01:00 |   1000K|00:00:00.22 |   17897 |  16878 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
--//根本没有理会提示。

4.加入过滤排除NULL值看看。

SCOTT@book> SELECT *  FROM (SELECT * FROM t  where cr_date is not null ORDER BY cr_date desc ) WHERE rownum <= 5;
    ID IDX CR_DATE             VC
------ --- ------------------- ----------------------------------------------------------------------------------------------------------
999900  88 2022-08-20 07:04:09 999900xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999899  23 2022-08-20 07:02:43 999899xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999898  89 2022-08-20 07:01:16 999898xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999897  24 2022-08-20 06:59:50 999897xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999896  98 2022-08-20 06:58:23 999896xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Plan hash value: 3230194292

------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |
------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |             |      1 |        |       |     4 (100)|          |      5 |00:00:00.01 |       6 |      1 |
|*  1 |  COUNT STOPKEY                |             |      1 |        |       |            |          |      5 |00:00:00.01 |       6 |      1 |
|   2 |   VIEW                        |             |      1 |      5 |   535 |     4   (0)| 00:00:01 |      5 |00:00:00.01 |       6 |      1 |
|   3 |    TABLE ACCESS BY INDEX ROWID| T           |      1 |    999K|   117M|     4   (0)| 00:00:01 |      5 |00:00:00.01 |       6 |      1 |
|*  4 |     INDEX FULL SCAN DESCENDING| I_T_CR_DATE |      1 |      5 |       |     3   (0)| 00:00:01 |      5 |00:00:00.01 |       4 |      1 |
------------------------------------------------------------------------------------------------------------------------------------------------
--//可以使用普通索引。

SCOTT@book> SELECT *  FROM (SELECT /*+ index(t IF_T_CR_DATE )*/ * FROM t where cr_date is not null ORDER BY cr_date desc ) WHERE rownum <= 5;
    ID IDX CR_DATE             VC
------ --- ------------------- ----------------------------------------------------------------------------------------------------------
999900  88 2022-08-20 07:04:09 999900xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999899  23 2022-08-20 07:02:43 999899xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999898  89 2022-08-20 07:01:16 999898xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999897  24 2022-08-20 06:59:50 999897xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999896  98 2022-08-20 06:58:23 999896xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Plan hash value: 3299198703
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |      |      1 |        |       |       | 32526 (100)|          |      5 |00:00:00.68 |   17897 |  16887 |       |       |          |
|*  1 |  COUNT STOPKEY          |      |      1 |        |       |       |            |          |      5 |00:00:00.68 |   17897 |  16887 |       |       |          |
|   2 |   VIEW                  |      |      1 |    999K|   102M|       | 32526   (1)| 00:06:31 |      5 |00:00:00.68 |   17897 |  16887 |       |       |          |
|*  3 |    SORT ORDER BY STOPKEY|      |      1 |    999K|   117M|   130M| 32526   (1)| 00:06:31 |      5 |00:00:00.68 |   17897 |  16887 |  1683K|   633K| 1495K (0)|
|*  4 |     TABLE ACCESS FULL   | T    |      1 |    999K|   117M|       |  4934   (1)| 00:01:00 |    999K|00:00:00.23 |   17897 |  16887 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
--//提示无效,并且还导致执行计划选择全表扫描,oracle这优化器优化方式也真奇怪了。
--//从这里也可以看出oracle的降序索引"很傻".更加提示降序索引不能乱用,适用的场景很少。

5.总结:
1.NULL在排序desc没有指定的情况下优先输出。
2.降序索引的适用范围很窄。

6.补充测试:
--//NULLS last 或者NULLs first的情况。

drop index i_t_cr_date;
drop index if_t_cr_date;

create index i_t_idx_cr_date on t(idx ,cr_date);
create index if_t_idx_cr_date on t(idx ,cr_date desc);

SCOTT@book> select index_name,index_type,blevel,leaf_blocks,distinct_keys,num_rows from dba_indexes where owner=user and table_name='T';
INDEX_NAME                     INDEX_TYPE                      BLEVEL LEAF_BLOCKS DISTINCT_KEYS   NUM_ROWS
------------------------------ --------------------------- ---------- ----------- ------------- ----------
I_T_IDX_CR_DATE                NORMAL                               2        3068        999964    1000000
IF_T_IDX_CR_DATE               FUNCTION-BASED NORMAL                2        3213        999964    1000000

SCOTT@book> SELECT *  FROM (SELECT * FROM t WHERE idx = 42 ORDER BY cr_date desc NULLS last ) WHERE rownum <=5;
    ID IDX CR_DATE             VC
------ --- ------------------- ----------------------------------------------------------------------------------------------------------
999884  42 2022-08-20 06:41:07 999884xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999698  42 2022-08-20 02:13:16 999698xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999543  42 2022-08-19 22:30:04 999543xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999382  42 2022-08-19 18:38:14 999382xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
999340  42 2022-08-19 17:37:45 999340xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Plan hash value: 3299198703
-------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |      |      1 |        |       |       |  5216 (100)|          |      5 |00:00:00.14 |   17897 |       |       |          |
|*  1 |  COUNT STOPKEY          |      |      1 |        |       |       |            |          |      5 |00:00:00.14 |   17897 |       |       |          |
|   2 |   VIEW                  |      |      1 |  10101 |  1055K|       |  5216   (1)| 00:01:03 |      5 |00:00:00.14 |   17897 |       |       |          |
|*  3 |    SORT ORDER BY STOPKEY|      |      1 |  10101 |  1213K|  1360K|  5216   (1)| 00:01:03 |      5 |00:00:00.14 |   17897 | 22528 | 22528 |20480  (0)|
|*  4 |     TABLE ACCESS FULL   | T    |      1 |  10101 |  1213K|       |  4933   (1)| 00:01:00 |  10225 |00:00:00.13 |   17897 |       |       |          |
-------------------------------------------------------------------------------------------------------------------------------------------------------------
--//使用全表扫描。

--//加入提示后:
SELECT *  FROM (SELECT /*+ index(t I_T_IDX_CR_DATE) */ * FROM t WHERE idx = 42 ORDER BY cr_date desc NULLS last ) WHERE rownum <=5;
Plan hash value: 1786862719
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name            | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                 |      1 |        |       |       |  8061 (100)|          |      5 |00:00:00.04 |    7806 |     35 |       |       |          |
|*  1 |  COUNT STOPKEY                 |                 |      1 |        |       |       |            |          |      5 |00:00:00.04 |    7806 |     35 |       |       |          |
|   2 |   VIEW                         |                 |      1 |  10101 |  1055K|       |  8061   (1)| 00:01:37 |      5 |00:00:00.04 |    7806 |     35 |       |       |          |
|*  3 |    SORT ORDER BY STOPKEY       |                 |      1 |  10101 |  1213K|  1360K|  8061   (1)| 00:01:37 |      5 |00:00:00.04 |    7806 |     35 | 22528 | 22528 |20480  (0)|
|   4 |     TABLE ACCESS BY INDEX ROWID| T               |      1 |  10101 |  1213K|       |  7779   (1)| 00:01:34 |  10225 |00:00:00.03 |    7806 |     35 |       |       |          |
|*  5 |      INDEX RANGE SCAN          | I_T_IDX_CR_DATE |      1 |  10101 |       |       |    33   (0)| 00:00:01 |  10225 |00:00:00.01 |      35 |     34 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--//实际上扫描索引(idx=42的全部),cost比前面全表扫描要高。

SELECT *  FROM (SELECT /*+ index(t IF_T_IDX_CR_DATE) */ * FROM t WHERE idx = 42 ORDER BY cr_date desc NULLS last ) WHERE rownum <=5;
Plan hash value: 1966750027
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name             | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                  |      1 |        |       |       |  8063 (100)|          |      5 |00:00:00.03 |    7807 |     35 |       |       |          |
|*  1 |  COUNT STOPKEY                 |                  |      1 |        |       |       |            |          |      5 |00:00:00.03 |    7807 |     35 |       |       |          |
|   2 |   VIEW                         |                  |      1 |  10101 |  1055K|       |  8063   (1)| 00:01:37 |      5 |00:00:00.03 |    7807 |     35 |       |       |          |
|*  3 |    SORT ORDER BY STOPKEY       |                  |      1 |  10101 |  1213K|  1360K|  8063   (1)| 00:01:37 |      5 |00:00:00.03 |    7807 |     35 |  2048 |  2048 | 2048  (0)|
|   4 |     TABLE ACCESS BY INDEX ROWID| T                |      1 |  10101 |  1213K|       |  7781   (1)| 00:01:34 |  10225 |00:00:00.02 |    7807 |     35 |       |       |          |
|*  5 |      INDEX RANGE SCAN          | IF_T_IDX_CR_DATE |      1 |  10101 |       |       |    35   (0)| 00:00:01 |  10225 |00:00:00.01 |      36 |     35 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--//可以使用,但是你对比前面的情况,可以发现使用降序索引毫无优势。

--//使用NULLS first设置实际上对于desc是缺省设置。
SELECT *  FROM (SELECT * FROM t WHERE idx = 42 ORDER BY cr_date desc NULLS first ) WHERE rownum<=5;

Plan hash value: 2332835607
--------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name            | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                 |      1 |        |       |     8 (100)|          |      5 |00:00:00.01 |       9 |
|*  1 |  COUNT STOPKEY                 |                 |      1 |        |       |            |          |      5 |00:00:00.01 |       9 |
|   2 |   VIEW                         |                 |      1 |      6 |   642 |     8   (0)| 00:00:01 |      5 |00:00:00.01 |       9 |
|   3 |    TABLE ACCESS BY INDEX ROWID | T               |      1 |  10101 |  1213K|     8   (0)| 00:00:01 |      5 |00:00:00.01 |       9 |
|*  4 |     INDEX RANGE SCAN DESCENDING| I_T_IDX_CR_DATE |      1 |      6 |       |     3   (0)| 00:00:01 |      5 |00:00:00.01 |       4 |
--------------------------------------------------------------------------------------------------------------------------------------------

--//即使提示看看。
SELECT *  FROM (SELECT /*+ index(t I_T_IDX_CR_DATE) */ * FROM t WHERE idx = 42 ORDER BY cr_date desc NULLS first ) WHERE rownum <=5;
Plan hash value: 1786862719
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name            | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                 |      1 |        |       |       |  8061 (100)|          |      5 |00:00:00.06 |    7806 |   1613 |       |       |          |
|*  1 |  COUNT STOPKEY                 |                 |      1 |        |       |       |            |          |      5 |00:00:00.06 |    7806 |   1613 |       |       |          |
|   2 |   VIEW                         |                 |      1 |  10101 |  1055K|       |  8061   (1)| 00:01:37 |      5 |00:00:00.06 |    7806 |   1613 |       |       |          |
|*  3 |    SORT ORDER BY STOPKEY       |                 |      1 |  10101 |  1213K|  1360K|  8061   (1)| 00:01:37 |      5 |00:00:00.06 |    7806 |   1613 | 22528 | 22528 |20480  (0)|
|   4 |     TABLE ACCESS BY INDEX ROWID| T               |      1 |  10101 |  1213K|       |  7779   (1)| 00:01:34 |  10225 |00:00:00.05 |    7806 |   1613 |       |       |          |
|*  5 |      INDEX RANGE SCAN          | I_T_IDX_CR_DATE |      1 |  10101 |       |       |    33   (0)| 00:00:01 |  10225 |00:00:00.01 |      35 |     32 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--//注意看不是INDEX RANGE SCAN DESCENDING,感觉oracle优化器还是不够智能。实际上正确的提示是:INDEX_DESC
SELECT *  FROM (SELECT /*+ index_desc(t I_T_IDX_CR_DATE) */ * FROM t WHERE idx = 42 ORDER BY cr_date desc NULLS first ) WHERE rownum <=5;
Plan hash value: 2332835607
--------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name            | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                 |      1 |        |       |     8 (100)|          |      5 |00:00:00.01 |       9 |
|*  1 |  COUNT STOPKEY                 |                 |      1 |        |       |            |          |      5 |00:00:00.01 |       9 |
|   2 |   VIEW                         |                 |      1 |      6 |   642 |     8   (0)| 00:00:01 |      5 |00:00:00.01 |       9 |
|   3 |    TABLE ACCESS BY INDEX ROWID | T               |      1 |      6 |   738 |     8   (0)| 00:00:01 |      5 |00:00:00.01 |       9 |
|*  4 |     INDEX RANGE SCAN DESCENDING| I_T_IDX_CR_DATE |      1 |  10101 |       |     3   (0)| 00:00:01 |      5 |00:00:00.01 |       4 |
--------------------------------------------------------------------------------------------------------------------------------------------

SELECT *  FROM (SELECT /*+ index(t IF_T_IDX_CR_DATE) */ * FROM t WHERE idx = 42 ORDER BY cr_date desc NULLS first ) WHERE rownum <=5;
Plan hash value: 313436017

-----------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |
-----------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |      1 |        |       |     8 (100)|          |      5 |00:00:00.01 |       9 |      3 |
|*  1 |  COUNT STOPKEY                |                  |      1 |        |       |            |          |      5 |00:00:00.01 |       9 |      3 |
|   2 |   VIEW                        |                  |      1 |      6 |   642 |     8   (0)| 00:00:01 |      5 |00:00:00.01 |       9 |      3 |
|   3 |    TABLE ACCESS BY INDEX ROWID| T                |      1 |  10101 |  1213K|     8   (0)| 00:00:01 |      5 |00:00:00.01 |       9 |      3 |
|*  4 |     INDEX RANGE SCAN          | IF_T_IDX_CR_DATE |      1 |      6 |       |     3   (0)| 00:00:01 |      5 |00:00:00.01 |       4 |      3 |
-----------------------------------------------------------------------------------------------------------------------------------------------------

--//再补充index_desc的情况:
SELECT *  FROM (SELECT /*+ index_desc(t I_T_IDX_CR_DATE) */ * FROM t WHERE idx = 42 ORDER BY cr_date desc NULLS last ) WHERE rownum <=5;

Plan hash value: 669288848
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name            | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                 |      1 |        |       |       |  8061 (100)|          |      5 |00:00:00.03 |    7806 |       |       |          |
|*  1 |  COUNT STOPKEY                  |                 |      1 |        |       |       |            |          |      5 |00:00:00.03 |    7806 |       |       |          |
|   2 |   VIEW                          |                 |      1 |  10101 |  1055K|       |  8061   (1)| 00:01:37 |      5 |00:00:00.03 |    7806 |       |       |          |
|*  3 |    SORT ORDER BY STOPKEY        |                 |      1 |  10101 |  1213K|  1360K|  8061   (1)| 00:01:37 |      5 |00:00:00.03 |    7806 |  2048 |  2048 | 2048  (0)|
|   4 |     TABLE ACCESS BY INDEX ROWID | T               |      1 |  10101 |  1213K|       |  7779   (1)| 00:01:34 |  10225 |00:00:00.02 |    7806 |       |       |          |
|*  5 |      INDEX RANGE SCAN DESCENDING| I_T_IDX_CR_DATE |      1 |  10101 |       |       |    33   (0)| 00:00:01 |  10225 |00:00:00.01 |      35 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--//提示有效,但是无法充分利用降序的特性优化语句。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/267265/viewspace-2678406/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
熟悉oracle相关技术,擅长sql优化,rman备份与恢复,熟悉linux shell编程。

注册时间:2008-01-03

  • 博文量
    4006
  • 访问量
    7969544