[20190918]关于函数索引问题.txt

来源:这里教程网 时间:2026-03-03 14:13:43 作者:

[20190918]关于函数索引问题.txt 1.环境: SCOTT@test01p> @ ver1 PORT_STRING                    VERSION        BANNER                                                                               CON_ID ------------------------------ -------------- -------------------------------------------------------------------------------- ---------- IBMPC/WIN_NT64-9.1.0           12.2.0.1.0     Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production              0 create table t as select 1 id1, rownum id2 ,'test' name from dual connect by level<1e4; insert into t values (1e4,1e4,'abcd'); commit ; create index if_t_id2 on t(decode(id1, 1, to_number(null), id2)); --//分析表略。 --//简单说明,使用to_number(null)保证返回数据类型是number类型的NULL值。 2.测试: SCOTT@test01p> select column_name,data_type from user_tab_cols where table_name = 'T' ; COLUMN_NAME          DATA_TYPE -------------------- ---------- ID1                  NUMBER ID2                  NUMBER NAME                 CHAR SYS_NC00004$         NUMBER --//增加一个隐含字段SYS_NC00004$.返回数据类型是number类型. SCOTT@test01p> alter session set statistics_level = all; Session altered. SCOTT@test01p> select * from t where decode(id1, 1,to_number(null), id2) = 1e4;        ID1        ID2 NAME ---------- ---------- --------------------      10000      10000 abcd SCOTT@test01p> @ dpc '' '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID  7srfk2yjdxx49, child number 0 ------------------------------------- select * from t where decode(id1, 1,to_number(null), id2) = 1e4 Plan hash value: 1601196873 -------------------------------------------------------------------------------------------------------------------- | Id  | Operation         | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | -------------------------------------------------------------------------------------------------------------------- |   0 | SELECT STATEMENT  |      |      1 |        |       |    10 (100)|          |      1 |00:00:00.01 |      31 | |*  1 |  TABLE ACCESS FULL| T    |      1 |    100 |  1200 |    10   (0)| 00:00:01 |      1 |00:00:00.01 |      31 | -------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): -------------------------------------------------------------    1 - SEL$1 / T@SEL$1 Predicate Information (identified by operation id): ---------------------------------------------------    1 - filter(DECODE("ID1",1,NULL,"ID2")=10000) --//你可以发现实际上filter(DECODE("ID1",1,NULL,"ID2")=10000). SCOTT@test01p> select * from user_ind_expressions where index_name = 'IF_T_ID2'   2  @prxx ============================== INDEX_NAME                    : IF_T_ID2 TABLE_NAME                    : T COLUMN_EXPRESSION             : DECODE("ID1",1,NULL,"ID2") COLUMN_POSITION               : 1 PL/SQL procedure successfully completed. --//你可以发现我建立的函数索引的表达式与保存的不一致. --//尝试改写看看呢? SCOTT@test01p> select * from t where decode(id1, 1,null, id2) = 1e4;        ID1        ID2 NAME ---------- ---------- --------------------      10000      10000 abcd SCOTT@test01p> @ dpc '' '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID  by0609fp41hy2, child number 0 ------------------------------------- select * from t where decode(id1, 1,null, id2) = 1e4 Plan hash value: 1130968923 ------------------------------------------------------------------------------------------------------------------------------------------ | Id  | Operation                           | Name     | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | ------------------------------------------------------------------------------------------------------------------------------------------ |   0 | SELECT STATEMENT                    |          |      1 |        |       |     2 (100)|          |      1 |00:00:00.01 |       2 | |   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |      1 |    13 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       2 | |*  2 |   INDEX RANGE SCAN                  | IF_T_ID2 |      1 |      1 |       |     1   (0)| 00:00:01 |      1 |00:00:00.01 |       1 | ------------------------------------------------------------------------------------------------------------------------------------------ Query Block Name / Object Alias (identified by operation id): -------------------------------------------------------------    1 - SEL$1 / T@SEL$1    2 - SEL$1 / T@SEL$1 Predicate Information (identified by operation id): ---------------------------------------------------    2 - access("T"."SYS_NC00004$"=10000) --//这样可以使用索引,而这样明显存在1个错误,按照Yangtingkun以前blog介绍,这样的返回类型是字符型.因为NULL没有明确指定 --//缺省类型是varchar2类型.而实际现在是number类型.是因为SYS_NC00004$是NUMBER类型. 3.继续测试: --//如果rebuild online索引呢? SCOTT@test01p> alter index IF_T_ID2 rebuild online ; Index altered. SCOTT@test01p> select * from t where decode(id1, 1,null, id2) = 1e4;        ID1        ID2 NAME ---------- ---------- --------------------      10000      10000 abcd SCOTT@test01p> @ dpc '' '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID  by0609fp41hy2, child number 0 ------------------------------------- select * from t where decode(id1, 1,null, id2) = 1e4 Plan hash value: 1601196873 -------------------------------------------------------------------------------------------------------------------- | Id  | Operation         | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | -------------------------------------------------------------------------------------------------------------------- |   0 | SELECT STATEMENT  |      |      1 |        |       |    11 (100)|          |      1 |00:00:00.01 |      31 | |*  1 |  TABLE ACCESS FULL| T    |      1 |      1 |    13 |    11  (10)| 00:00:01 |      1 |00:00:00.01 |      31 | -------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): -------------------------------------------------------------    1 - SEL$1 / T@SEL$1 Predicate Information (identified by operation id): ---------------------------------------------------    1 - filter(TO_NUMBER(DECODE("ID1",1,NULL,TO_CHAR("ID2")))=10000) --//注意看过滤条件,发生了隐式转换.前面加上了TO_NUMBER. SCOTT@test01p> select column_name,data_type from user_tab_cols where table_name = 'T' ; COLUMN_NAME          DATA_TYPE -------------------- -------------------- ID1                  NUMBER ID2                  NUMBER NAME                 CHAR SYS_NC00004$         VARCHAR2 --//重建索引后,隐含字段SYS_NC00004$的数据类型对比前面的情况发生了变化,变为varchar2类型. --//要保证使用索引应该写成如下: SCOTT@test01p> select * from t where decode(id1, 1,null, id2) = to_char(1e4);        ID1        ID2 NAME ---------- ---------- --------------------      10000      10000 abcd SCOTT@test01p> @ dpc '' '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID  63zyt23ufr2xa, child number 0 ------------------------------------- select * from t where decode(id1, 1,null, id2) = to_char(1e4) Plan hash value: 1130968923 ------------------------------------------------------------------------------------------------------------------------------------------ | Id  | Operation                           | Name     | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | ------------------------------------------------------------------------------------------------------------------------------------------ |   0 | SELECT STATEMENT                    |          |      1 |        |       |     2 (100)|          |      1 |00:00:00.01 |       2 | |   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |      1 |    13 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       2 | |*  2 |   INDEX RANGE SCAN                  | IF_T_ID2 |      1 |      1 |       |     1   (0)| 00:00:01 |      1 |00:00:00.01 |       1 | ------------------------------------------------------------------------------------------------------------------------------------------ Query Block Name / Object Alias (identified by operation id): -------------------------------------------------------------    1 - SEL$1 / T@SEL$1    2 - SEL$1 / T@SEL$1 Predicate Information (identified by operation id): ---------------------------------------------------    2 - access("T"."SYS_NC00004$"='10000')

相关推荐