28.读书笔记收获不止Oracle之 函数索引

来源:互联网 发布:淘宝洗照片不好 编辑:程序博客网 时间:2024/04/20 13:31

28.读书笔记收获不止Oracle之 函数索引

先来看个例子:

SQL> drop table t purge;

Table dropped.

SQL> create table t as select * from dba_objects;

Table created.

SQL> create index idx_object_id on t(object_id);

Index created.

SQL> create index idx_object_name on t(object_name);

Index created.

SQL> create index idx_createed on t(created);

Index created.

SQL> select count(*) from t;

 COUNT(*)

----------

    90945

SQL> set autotrace traceonly

SQL> set linesize 1000

SQL> select * from t whereupper(object_name)='T';

Execution Plan

----------------------------------------------------------

Plan hash value: 1601196873

 

--------------------------------------------------------------------------

| Id | Operation                    | Name | Rows | Bytes | Cost (%CPU)| Time           |

--------------------------------------------------------------------------

|   0| SELECT STATEMENT  |       |  909 |   102K|   426  (1)| 00:00:01 |

|*  1|  TABLE ACCESS FULL| T      |  909 |   102K|   426  (1)| 00:00:01 |

--------------------------------------------------------------------------

 

Predicate Information (identified byoperation id):

---------------------------------------------------

 

   1- filter(UPPER("OBJECT_NAME")='T')

 

 

Statistics

----------------------------------------------------------

                    1 recursive calls

                    0  dbblock gets

      1533  consistent gets

                    0 physical reads

                    0  redosize

      1851  bytes sent via SQL*Net toclient

                  551  bytes received via SQL*Net from client

                    2 SQL*Net roundtrips to/from client

                    0 sorts (memory)

                    0 sorts (disk)

                    1  rowsprocessed

走的全表扫描,没有走索引。去掉UPPER函数执行如下

SQL> select * from t where object_name='T';

Execution Plan

----------------------------------------------------------

Plan hash value: 603483963

-------------------------------------------------------------------------------------------------------

| Id | Operation                                                          | Name                 | Rows | Bytes | Cost (%CPU)| Time     |

-------------------------------------------------------------------------------------------------------

|   0| SELECT STATEMENT                                    |                              |    2 |   230 |     4   (0)|00:00:01 |

|   1|  TABLE ACCESS BY INDEX ROWID BATCHED| T                  |    2 |   230 |     4   (0)|00:00:01 |

|*  2|   INDEX RANGESCAN                               | IDX_OBJECT_NAME |     2 |      |     3                (0)| 00:00:01 |

-------------------------------------------------------------------------------------------------------

Predicate Information (identified byoperation id):

---------------------------------------------------

   2- access("OBJECT_NAME"='T')

Statistics

----------------------------------------------------------

                    1 recursive calls

                    0  dbblock gets

                    5 consistent gets

                    2 physical reads

                    0  redosize

      1855  bytes sent via SQL*Net toclient

                  551  bytes received via SQL*Net from client

                    2 SQL*Net roundtrips to/from client

                    0 sorts (memory)

                    0 sorts (disk)

                    1  rowsprocessed

 

发现,因为UPPER函数,导致无法使用索引,这个是因为对所有列做运算导致索引无法使用。

如果OBJECT_NAME列不存在小写字母,则SELECT *FROM T WHERE OBJECT_NAME=’T’ 和SELECT *FROM T WHEREUPPER(OBJECT_NAME)=’T’ 是完全等价的。如果还写UPPER就是多此一举又影响性能。

1.  函数索引

                  如果OBJECT_NAME列的取值真的有大有小,需要UPPER函数来执行,就需要函数索引了。

                  函数索引的方法很简单,和普通索引的方法类似,区别在于用函数运算替代列名。具体看如下例子:

SQL> create index idx_upper_obj_name on t (upper(object_name));

 

Index created.

 

SQL> select * from t where upper(object_name)='T';

 

 

Execution Plan

----------------------------------------------------------

Plan hash value: 2908766729

 

----------------------------------------------------------------------------------------------------------

| Id | Operation                                                          | Name                             | Rows  | Bytes | Cost (%CPU)| Time            |

----------------------------------------------------------------------------------------------------------

|   0| SELECT STATEMENT                                    |                                          |   909 |   102K|  193   (0)| 00:00:01 |

|   1|  TABLE ACCESS BY INDEX ROWID BATCHED| T                               |   909|   102K|   193  (0)| 00:00:01 |

|*  2|   INDEX RANGE SCAN                               | IDX_UPPER_OBJ_NAME |   364 |       |     3  (0)| 00:00:01 |

----------------------------------------------------------------------------------------------------------

 

Predicate Information (identified byoperation id):

---------------------------------------------------

 

   2- access(UPPER("OBJECT_NAME")='T')

 

 

Statistics

----------------------------------------------------------

                    5 recursive calls

                    0  dbblock gets

                    7 consistent gets

                    2 physical reads

                    0  redosize

      1851  bytes sent via SQL*Net toclient

                  551  bytes received via SQL*Net from client

                    2 SQL*Net roundtrips to/from client

                    0 sorts (memory)

                    0 sorts (disk)

                    1  rowsprocessed

 

使用函数索引了,代价是193,B树索引代价是4,全表扫描代价是426.

来查看索引类型如下:

SQL>  selectindex_name,index_type from user_indexes where table_name='T';

 

INDEX_NAME        INDEX_TYPE

--------------- ---------------------------

IDX_OBJECT_ID     NORMAL

IDX_OBJECT_NAME NORMAL

IDX_CREATEED      NORMAL

IDX_UPPER_OBJ_N FUNCTION-BASED NORMAL

AME

                  在大多数情况下,对列进行函数运算的SQL写法都是可以转换成对列不做运算的不同写法。

2.  避免列运算1

函数索引在很多情况下,是对列进行运算。函数索引性能介于普通索引和全表扫描之间,能用普通索引就尽量用普通索引。

2.1      实验1

SQL> set autotrace traceonly

SQL> set linesize 1000

SQL> select * from t where object_id-10<=30;

39 rows selected.

Execution Plan

----------------------------------------------------------

Plan hash value: 1601196873

 

--------------------------------------------------------------------------

| Id | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time           |

--------------------------------------------------------------------------

|   0| SELECT STATEMENT  |       | 4547 |   510K|   426  (1)| 00:00:01 |

|*  1|  TABLE ACCESS FULL| T      |  4547 |   510K|  426   (1)| 00:00:01 |

--------------------------------------------------------------------------

 

Predicate Information (identified byoperation id):

---------------------------------------------------

 

   1- filter("OBJECT_ID"-10<=30)

 

 

Statistics

----------------------------------------------------------

                    1 recursive calls

                    0  dbblock gets

      1535  consistent gets

                    0 physical reads

                    0  redosize

      3725  bytes sent via SQL*Net toclient

                  573  bytes received via SQL*Net from client

                    4 SQL*Net roundtrips to/from client

                    0 sorts (memory)

                    0 sorts (disk)

                   39  rowsprocessed

 

2.2      实验2

SQL> select * from t where object_id<=40;

 

39 rows selected.

 

 

Execution Plan

----------------------------------------------------------

Plan hash value: 1296629646

 

-----------------------------------------------------------------------------------------------------

| Id | Operation                                                          | Name               | Rows | Bytes | Cost (%CPU)| Time     |

-----------------------------------------------------------------------------------------------------

|   0| SELECT STATEMENT                                    |                            |      39 |  4485 |         4   (0)| 00:00:01 |

|   1|  TABLE ACCESS BY INDEX ROWID BATCHED| T                |      39 |  4485 |         4   (0)| 00:00:01 |

|*  2|   INDEX RANGE SCAN                               | IDX_OBJECT_ID |      39 |           |        2  (0)| 00:00:01 |

-----------------------------------------------------------------------------------------------------

 

Predicate Information (identified byoperation id):

---------------------------------------------------

 

   2- access("OBJECT_ID"<=40)

 

 

Statistics

----------------------------------------------------------

                    1 recursive calls

                    0  dbblock gets

                    9 consistent gets

                    1 physical reads

                    0  redosize

      5890  bytes sent via SQL*Net toclient

                  573  bytes received via SQL*Net from client

                    4 SQL*Net roundtrips to/from client

                    0 sorts (memory)

                    0 sorts (disk)

                   39  rowsprocessed

 

同样的结果,不同的写法导致性能差异。

建立索引试试

2.3      实验3

Create index idx_object_id_2 on t(object_id -10);

SQL> select * from t where object_id-10<=30;

 

39 rows selected.

 

 

Execution Plan

----------------------------------------------------------

Plan hash value: 865720425

 

-------------------------------------------------------------------------------------------------------

| Id | Operation                                                          | Name                 | Rows | Bytes | Cost (%CPU)| Time     |

-------------------------------------------------------------------------------------------------------

|   0| SELECT STATEMENT                                    |                              | 4547 |   510K|    26 (0)|00:00:01 |

|   1|  TABLE ACCESS BY INDEX ROWID BATCHED| T                  | 4547 |   510K|    26 (0)|00:00:01 |

|*  2|   INDEX RANGE SCAN                               | IDX_OBJECT_ID_2 |   819 |      |     3 (0)| 00:00:01 |

-------------------------------------------------------------------------------------------------------

 

Predicate Information (identified byoperation id):

---------------------------------------------------

 

   2- access("OBJECT_ID"-10<=30)

 

 

Statistics

----------------------------------------------------------

                    2 recursive calls

                    0  dbblock gets

                   11 consistent gets

                    1 physical reads

                    0  redosize

      3513  bytes sent via SQL*Net toclient

                  573  bytes received via SQL*Net from client

                    4 SQL*Net roundtrips to/from client

                    0 sorts (memory)

                    0 sorts (disk)

                   39  rowsprocessed

 

 

3.  避免列运算2

SQL> select * from t where substr(object_name,1,4)='CLUS';

Execution Plan

----------------------------------------------------------

Plan hash value: 1601196873

 

--------------------------------------------------------------------------

| Id | Operation                    | Name | Rows | Bytes | Cost (%CPU)| Time           |

--------------------------------------------------------------------------

|   0| SELECT STATEMENT  |       |    6 |   690 |   426  (1)| 00:00:01 |

|*  1|  TABLE ACCESS FULL| T      |    6 |   690 |   426  (1)| 00:00:01 |

--------------------------------------------------------------------------

 

Predicate Information (identified byoperation id):

---------------------------------------------------

 

   1- filter(SUBSTR("OBJECT_NAME",1,4)='CLUS')

 

Note

-----

   -dynamic statistics used: dynamic sampling (level=2)

   -1 Sql Plan Directive used for this statement

 

 

Statistics

----------------------------------------------------------

                   18 recursive calls

                    0  dbblock gets

      2308  consistent gets

                    0 physical reads

                    0  redosize

      2049  bytes sent via SQL*Net toclient

                  551  bytes received via SQL*Net from client

                    2 SQL*Net roundtrips to/from client

                    1 sorts (memory)

                    0 sorts (disk)

                    3  rowsprocessed

除非建立一个SUBSTR相关函数的索引,否则用不上索引。

不过还可以使用如下命令进行避免

SQL> select * from t where object_name like 'CLUS%';

Execution Plan

----------------------------------------------------------

Plan hash value: 603483963

 

-------------------------------------------------------------------------------------------------------

| Id | Operation                                                          | Name                 | Rows | Bytes | Cost (%CPU)| Time     |

-------------------------------------------------------------------------------------------------------

|   0| SELECT STATEMENT                                    |                              |    2 |   290 |     4   (0)|00:00:01 |

|   1|  TABLE ACCESS BY INDEX ROWID BATCHED| T                  |    2 |   290 |     4   (0)|00:00:01 |

|*  2|   INDEX RANGE SCAN                               | IDX_OBJECT_NAME |     2 |      |     3                (0)| 00:00:01 |

-------------------------------------------------------------------------------------------------------

 

Predicate Information (identified byoperation id):

---------------------------------------------------

 

   2- access("OBJECT_NAME" LIKE 'CLUS%')

       filter("OBJECT_NAME" LIKE 'CLUS%')

 

 

Statistics

----------------------------------------------------------

      1831  recursive calls

                    0  dbblock gets

      1676  consistent gets

                    8 physical reads

                    0  redosize

      2136  bytes sent via SQL*Net toclient

                  551  bytes received via SQL*Net from client

                    2 SQL*Net roundtrips to/from client

                   67 sorts (memory)

                    0 sorts (disk)

                    3  rowsprocessed

4.  避免列运算3

看如下脚本

SQL> select * from t where trunc(created)>=TO_DATE('2012-10-02','YYYY-MM-DD') and trunc(created) <=TO_DATE('2012-10-03','YYYY-MM-DD');

 

no rows selected

 

 

Execution Plan

----------------------------------------------------------

Plan hash value: 1601196873

 

--------------------------------------------------------------------------

| Id | Operation                    | Name | Rows | Bytes | Cost (%CPU)| Time           |

--------------------------------------------------------------------------

|   0| SELECT STATEMENT  |       |  227 | 32915 |   428   (1)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| T      |  227 | 32915 |   428   (1)| 00:00:01 |

--------------------------------------------------------------------------

 

Predicate Information (identified byoperation id):

---------------------------------------------------

 

   1- filter(TRUNC(INTERNAL_FUNCTION("CREATED"))>=TO_DATE(' 2012-10-02

                        00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND

                       TRUNC(INTERNAL_FUNCTION("CREATED"))<=TO_DATE(' 2012-10-0300:00:00',

                        'syyyy-mm-dd hh24:mi:ss'))

 

 

Statistics

----------------------------------------------------------

                   11 recursive calls

                    0  dbblock gets

      1536  consistent gets

                  117  physical reads

                    0  redosize

      1572  bytes sent via SQL*Net toclient

                  540  bytes received via SQL*Net from client

                    1 SQL*Net roundtrips to/from client

                    0 sorts (memory)

                    0 sorts (disk)

                    0  rowsprocessed

没有走索引,不过可以使用相同的办法实现相同的功能如下:

SQL>  select * from t wherecreated>= TO_DATE('2012-10-02','YYYY-MM-DD') and created < TO_DATE('2012-10-03','YYYY-MM-DD')+1;

 

no rows selected

 

 

Execution Plan

----------------------------------------------------------

Plan hash value: 3369967073

 

----------------------------------------------------------------------------------------------------

| Id | Operation                                                          | Name              | Rows | Bytes | Cost (%CPU)| Time          |

----------------------------------------------------------------------------------------------------

|   0| SELECT STATEMENT                                    |                           |  143 | 20735 |         5   (0)| 00:00:01 |

|   1|  TABLE ACCESS BY INDEX ROWID BATCHED| T               |  143 | 20735 |         5   (0)| 00:00:01 |

|*  2|   INDEX RANGE SCAN                               | IDX_CREATEED |   143 |         |        2   (0)| 00:00:01 |

----------------------------------------------------------------------------------------------------

 

Predicate Information (identified byoperation id):

---------------------------------------------------

 

   2- access("CREATED">=TO_DATE(' 2012-10-02 00:00:00', 'syyyy-mm-ddhh24:mi:ss') AND

                        "CREATED"<TO_DATE('2012-10-04 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))

 

 

Statistics

----------------------------------------------------------

                   11 recursive calls

                    0  dbblock gets

                    6 consistent gets

                    2 physical reads

                    0  redosize

      1572  bytes sent via SQL*Net toclient

                  540  bytes received via SQL*Net from client

                    1 SQL*Net roundtrips to/from client

                    0 sorts (memory)

                    0 sorts (disk)

                    0  rowsprocessed

                  执行就走索引了。

阅读全文
0 0
原创粉丝点击