当前位置: 首页 > news >正文

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

相关文章:

  • 在同一个页面父窗口打开子窗口,动态无刷新提交,超炫基于jquery ajax提交,兼容IE7+,火狐.....
  • PHP统计目录下的文件总数及代码行数(去除注释及空行)
  • nyoj 523 双向广搜
  • JS调用后台方法大全
  • 即时通信3
  • frame-relay实验
  • eclipse启动不了报错java was started but returned exit code=13
  • GDAL编译Windows平台下64位的方式
  • java调用webservice
  • 使用JSR234实现对图片的缩放
  • 《大型分布式网站架构设计与实践》
  • 迷路
  • SQL Server 高可用使用环境
  • Java基础之异常
  • 心情流水账
  • 5、React组件事件详解
  • Hexo+码云+git快速搭建免费的静态Blog
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • Java深入 - 深入理解Java集合
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Odoo domain写法及运用
  • 分享一份非常强势的Android面试题
  • 讲清楚之javascript作用域
  • 前端代码风格自动化系列(二)之Commitlint
  • 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
  • 消息队列系列二(IOT中消息队列的应用)
  • 协程
  • 优秀架构师必须掌握的架构思维
  • AI算硅基生命吗,为什么?
  • SAP CRM里Lead通过工作流自动创建Opportunity的原理讲解 ...
  • 大数据全解:定义、价值及挑战
  • (14)Hive调优——合并小文件
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (C#)获取字符编码的类
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (动态规划)5. 最长回文子串 java解决
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (四)linux文件内容查看
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .NET 分布式技术比较
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • @SuppressWarnings(unchecked)代码的作用
  • []C/C++读取串口接收到的数据程序
  • [20190401]关于semtimedop函数调用.txt
  • [acwing周赛复盘] 第 94 场周赛20230311
  • [Android View] 可绘制形状 (Shape Xml)
  • [Android]使用Retrofit进行网络请求
  • [Android实例] 保持屏幕长亮的两种方法 [转]
  • [BZOJ4554][TJOI2016HEOI2016]游戏(匈牙利)