Oracle的隐式转换

都说Oracle存在NUMBER和VARCHAR2类型的隐式转换,严格意义上需要避免,但为何需要避免,从下面的实验进行验证。

1. 创建测试表和索引
create table tn (id number, name varchar2(1));

create index idx_tn on tn (id);

create index idx_tn on tn (name);
分别对NUMBER类型的id字段,VARCHAR2类型的name字段创建索引。

2. 查看VARCHAR2->NUMBER的隐式转换

SQL> select * from tn where id = 1;

no rows selected

Execution Plan

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

Plan hash value: 3532270966

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

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

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

| 0 | SELECT STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |

|* 1 | INDEX RANGE SCAN| IDX_TN | 1 | 13 | 1 (0)| 00:00:01 |

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

"where id = 1"用的是列索引范围扫描。

SQL> select * from tn where id = '123';

no rows selected

Execution Plan

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

Plan hash value: 3532270966

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

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

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

| 0 | SELECT STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |

|* 1 | INDEX RANGE SCAN| IDX_TN | 1 | 13 | 1 (0)| 00:00:01 |

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

"where id = '123'",Oracle会将字符类型的123转换为NUMBER类型进行比较,此处仍可使用索引范围扫描,说明VARCHAR2->NUMBER的隐式转换,未对索引产生影响

3. 查看NUMBER->VARCHAR2的隐式转换

SQL> select * from tn where name = '123';

no rows selected

Execution Plan

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

Plan hash value: 479240418

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

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

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

| 0 | SELECT STATEMENT | | 1 | 15 | 1 (0)| 00:00:01 |

| 1 | TABLE ACCESS BY INDEX ROWID| TN | 1 | 15 | 1 (0)| 00:00:01 |

|* 2 | INDEX RANGE SCAN | IDX_TN_NAME | 1 | | 1 (0)| 00:00:01 |

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

"where name = '123'"使用的是索引范围扫描。

SQL> select * from tn where name = 123;

no rows selected

Execution Plan

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

Plan hash value: 2655062619

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

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

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

| 0 | SELECT STATEMENT | | 1 | 15 | 2 (0)| 00:00:01 |

|* 1 | TABLE ACCESS FULL| TN | 1 | 15 | 2 (0)| 00:00:01 |

--------------------------------------------------------------------------
"where name = 123",Oracle会将数值类型的123转换为VARCHAR2字符类型,和name进行比较,此处用了全表扫描,说明name的列索引失效

总结
1. NAME和VARCHAR2之间可以进行隐式转换,其中VARCHAR2->NUMBER不会导致索引失效,NUMBER->VARCHAR2会让索引失效,因此这种隐式转换,是需要注意避免。
2. 之所以VARCHAR2->NUMBER不会让索引失效,我猜测是转换为where id = to_number('123')。NUMBER->VARCHAR2会让索引失效,我猜测是转换为where to_number(name) = 123。
3. 引申知识点,之所以上面id和name使用的是索引范围扫描,是因为建立的是非唯一B树索引,如果是unique索引,则会使用UNIQUE INDEX SCAN的扫描方式。

补充:
经lhrbest的指正,从谓词条件即可看出端倪。
​附:
​SQL> select * from tn where id = '123';
​Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ID"=123)

​SQL> select * from tn where name = 123;
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(TO_NUMBER("NAME")=123)
​可以看出此处对NAME做了TO_NUMBER转换,导致索引失效。

时间: 2024-10-25 12:49:11

Oracle的隐式转换的相关文章

MySQL和Oracle中的隐式转换

今天在处理一个问题的时候,需要根据其他部门提供的sql语句对一个表中的数据进行了筛查. 语句类似下面的形式 > SELECT MAX_LEVEL,LOGOUT_TIME,CURRENT_DATE AS NOWTIME,cn_master FROM t_test_october_back_a WHERE ID in ( 100, 200, 300, 400, 500) ; +-----------+---------------+------------+-----------+ | MAX_LE

从Java的类型转换看MySQL和Oracle中的隐式转换(二)

说起数据类型转换,在开发中如此,在数据库中也是如此,之前简单对比过MySQL和Oracle的数据类型转换情况,可以参见MySQL和Oracle中的隐式转换 http://blog.itpub.net/23718752/viewspace-1787973/ 不过当时写完之后,有个读者随口问了一句为什么,为什么呢?似乎自己还是一知半解,说是规则,无规矩不成方圆,倒也无可非议,不过我觉得还是要再看看,看看还能有哪些收获,接下来的内容我就不能保证正确性了,希望大家明辨,也希望提出意见,毕竟就是希望把问题

Oracle中的数据类型隐式转换(implicit conversion)

和其他的关系型数据库一样,oracle中也能进行一些隐式的数据转换,这对我们写SQL语句有非常用,我们可以不必麻烦地手动转化很多类型的字符.虽然前面我们介绍了一些使用例如to_char,to_date的函数进行强制转换的方法,但是隐式转换也还是不错的. Oracle可以隐式地进行一些变量类别之间转化,例如从字符串转换到数值,看下面的例子. SQL> select ename,sal from emp where sal = '1100′;   ENAME SAL ------– ---- SMI

Oracle隐式转换会影响物化视图查询重写

今天有人问我一个物化视图查询重写的问题,最后发现问题其实和物化视图的功能没有多大的关系,而是隐式转换导致的问题. 还是通过例子来说明这个问题: SQL> create table t ( 2  id number, 3  time date, 4  other varchar2(4000)) 5  partition by range (time) 6  (partition p1 values less than (to_date('2008-1-1', 'yyyy-mm-dd')), 7  

ORACLE绑定变量隐式转换导致性能问题

   年后一次系统升级后,监控数据库的工具DPA发现数据库的Total Wait时间突然飙增,如下截图所示,数据库的总体等待时间对比升级前飙增了非常多 另 外就是发现出现了较多的等待事件,主要有latch: cache buffers chains. latch: shared pool .db file scattered read.根据这边的监控发现TOP SQL里面从升级前的0次变为了一天的一万多次(有些甚至更多),分析过后我们就找开发人员了解一下系统升级变跟的内容和改动 开 发人员坚定的

[20140116]视图?隐式转换?sql优化问题.txt

[20140116]视图?隐式转换?sql优化问题.txt 最近一直在优化单位的垃圾数据库,这个数据库可以讲是一个垃圾工程.在有优化的过程遇到视图中存在隐式转化问题,在我的测试环境模 拟出来,提出解决方案: 1.建立测试环境: SCOTT@test> @ver BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise

第3课 隐式转换

1)val array=Array(1,2,3,4,5); array.map(item => 2*item);map的作用是循环遍历array中的每一个元素,并把每个元素做为具体的值传给map中的做为参数的函数.map执行结果为Array[Int] =Array(2,4,6,8,10);函数的参数也是函数,item时匿名函数,这个也是高阶函数 2)高阶函数的返回值也可能是函数.高阶函数的参数是函数,这是高阶函数的2个层面.高阶函数可以自动推断出函数参数的类型.而且对只有一个参数的函数,可以省略

JavaScript的隐式转换

JavaScript的数据类型分为六种,分别为null,undefined,boolean,string,number,object.object是引用类型,其它的五种是基本类型或者是原始类型.我们可以用typeof方法打印来某个是属于哪个类型的.不同类型的变量比较要先转类型,叫做类型转换,类型转换也叫隐式转换.隐式转换通常发生在运算符加减乘除,等于,还有小于,大于等.. typeof '11'  //string       typeof(11) //number '11' < 4     /

struct-c# 在一个实现了隐式转换的结构体进行强制类型转换时报错

问题描述 c# 在一个实现了隐式转换的结构体进行强制类型转换时报错 50C 如题,我有一个结构体,类似这样: public struct AInt{ private int _a; public int ToInt() { reurn _a; } public static implicit operator int(AInt value) { return value.ToInt(); } public static implicit operator AInt(int value) { _a