首页 > 数据库 >Oracle的隐式转换

Oracle的隐式转换

时间:2023-06-19 14:05:39浏览次数:43  
标签:00 转换 name NUMBER id 123 Oracle where 隐式

都说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转换,导致索引失效。


标签:00,转换,name,NUMBER,id,123,Oracle,where,隐式
From: https://blog.51cto.com/u_13950417/6512797

相关文章

  • 一次SQL_ID和HASH_VALUE转换尝试引发的误区
    这篇文章中曾谈到一个隐藏问题:引用原文:“使用@dbsnake大牛的SQL可以知道SQL_ID和HASH_VALUE的一一对应关系:隐藏问题1:这里的截图可能有点问题,结果并不准确,问题就出在这个SQL中使用的算法中,在另一篇博文中会仔细说明这个问题。”问题背景:这里使用以下两个SQL获取SQL_ID对应的HASH_VAL......
  • 《Oracle Concept》第三章 - 6
    背景:按照《OracleConecpt》的结构一起了解Oracle数据库,这是学习Oracle从入门到精通的基础。本文主题:第三章《IndexesandIndex-OrganizedTables》-OverviewofIndexes。索引范围扫描索引范围扫描是一种按序扫描索引的方式,具有如下特征:在检索条件中指定了索引中的一个或者更多......
  • 《Oracle Concept》第三章 - 10
    背景:按照《OracleConecpt》的结构一起了解Oracle数据库,这是学习Oracle从入门到精通的基础。本文主题:第三章《IndexesandIndex-OrganizedTables》-OverviewofIndexes。键值压缩技术Oracle能支持使用键值压缩技术对B树索引或者索引组织表中的主键列值部分进行压缩。键值压缩......
  • 《Oracle Concept》第三章 - 8
    背景:按照《OracleConecpt》的结构一起了解Oracle数据库,这是学习Oracle从入门到精通的基础。本文主题:第三章《IndexesandIndex-OrganizedTables》-OverviewofIndexes。反向索引反向索引也是一种B-树类型的索引,和普通B-树索引不同的是,他会在物理层上将每个索引键值的字节逆序......
  • 《Oracle Concept》第三章 - 5
    背景:按照《OracleConecpt》的结构一起了解Oracle数据库,这是学习Oracle从入门到精通的基础。本文主题:第三章《IndexesandIndex-OrganizedTables》-OverviewofIndexes。索引扫描在索引扫描中,数据库会在语句中指定索引列值,遍历索引来提取数据。如果数据库扫描索引,他会消耗N次I......
  • 如何根据v$parameter查询Oracle隐含参数
    Oracle的隐含参数在Oracle的官方文档中是不会出现的,这些参数主要是Oracle内部用于控制某些功能的开关,或者就像今天eygle讲的,Oracle牛逼之处就是可能几年前开发的一个功能就放到当时的版本中,让你“试用”,但你却不知道,如果碰巧因为遇见了这个问题的bug,Oracle会告诉你可以使用这个参数......
  • Oracle的体系结构图万花筒
    虽然现在Oracle的版本频繁更新,但万变不离其宗,学习Oracle最重要的一张图就是Oracle体系结构图,由他延展开来的知识可谓是相当丰富,要是能讲清楚这张图,可以说你和大师很近了。这是来自杨大师公众号的一篇文章,汇总了各版本,Oracle高清体系结构图,《【图示篇】_Oracle10g,11g,12c,18c结构......
  • 非Oracle Linux下安装Oracle 19c
    《Oracle19c之RPM安装》介绍了在OracleLinux平台下安装Oracle19c的过程,其实无论是19c,还是11g,用OracleLinux会为你省不少的事情,毕竟同为Oracle产品,从推广角度看,肯定会相对其他平台提供更多的便利性,例如提前预安装了需要的Package,设置了信号量,创建了各种账号、路径和权限。这次采......
  • OpenJDK和Oracle JDK有什么区别和联系?
    《Linux7安装Oracle11g打怪经历》的安装过程中,启动图形界面,需要指定jre路径,当时使用yuminstalljdk安装的,并不能解决问题,查看版本才知道他是OpenJDK,最终使用OracleJDK,才解决的问题,那OpenJDK和OracleJDK究竟有什么区别?OpenJDKJava最早由SUN公司(SunMicrosystems,发起于美国斯坦......
  • Linux 7安装Oracle 11g打怪经历
    最近接到个需求,要将一套开发环境中Linux6平台的Oracle11g,迁移到两套Linux7平台,原以为很简单,但过程中,确实历经坎坷,就像过山车一般,解决这个问题,又碰到下一个。软件信息RedHatLinux7.5Oracle11.2.0.4坑坑坑1.软链接为了安装路径的标准和简便,可以使用软链接,语法如下,ln-s【目标......