前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >如何找到隐式转换的SQL?

如何找到隐式转换的SQL?

作者头像
bisal
发布2021-09-06 15:48:33
发布2021-09-06 15:48:33
1.1K00
代码可运行
举报
运行总次数:0
代码可运行

隐式转换相关的文章,

从隐式转换案例,来挖掘开发人员的技能提升

浅谈显式转换和隐式转换

隐式转换的案例场景

我们知道,隐式转换是在开发过程中非常容易进的一种坑,最常见的就是程序中传参类型和数据库表中定义的字段类型不一致,隐患就是不能用到隐式转换字段上的索引,原先能使用索引的语句,却使用了全表,影响执行性能。

通常有以下三种场景可能出现隐式转换,

场景1

where varchar2=number,此时会在=左值使用to_number函数,谓词会显示TO_NUMBER(varchar2)=:1。

场景2

where varchar2=nvarchar2,此时会在=左值使用sys_op_c2c函数,谓词会出现SYS_OP_C2C(varchar2)=:1。

可参考《一次有意思的错选执行计划问题定位》。

场景3

where date=timestamp,此时会在=左值使用internal_function函数,谓词会出现INTERNAL_FUNCTION(date)=:1。

然而不是所有出现这些函数的场景都是因为隐式转换,例如这个SQL,

代码语言:javascript
代码运行次数:0
运行
复制
SQL> select * from t1 where col in ('A','B','C') and id=1;
        ID COL
---------- ---------------
         1 A

从执行计划的谓词信息中,可以看到,确实用到了INTERNAL_FUNCTION,但是和上述隐式转换的场景是不同的。这种IN多值的情况,算是一种“复杂”的复合谓词,如果用display_cursor显示执行计划,他是不知道怎么解释,因此用了INTERNAL_FUNCTION标识,

代码语言:javascript
代码运行次数:0
运行
复制
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |       |       |     3 (100)|          |
|*  1 |  TABLE ACCESS FULL| T1   |     1 |    15 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------
...
1 - filter((INTERNAL_FUNCTION("COL") AND "ID"=1))
...

但是如果用explain plan的方式检索执行计划,就可以从谓词信息中看到,IN转换为OR,而不是出现INTERNAL_FUNCTION,

代码语言:javascript
代码运行次数:0
运行
复制
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    15 |     2   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T1   |     1 |    15 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(("COL"='A' OR "COL"='B' OR "COL"='C') AND "ID"=1)

因此不能单从谓词信息判断是否出现了隐式转换,还是存在一些前提条件的,我不确定是否存在其他更加隐蔽的场景。如果想从Oracle中找到出现了隐式转换并且对性能产生影响(之所以说”并且“,就是因为如果是=右值出现隐式转换,至少不会影响索引的使用)的SQL,单靠一条SQL,确实有些困难。

因此我结合网上资料,设想了这种逻辑,

1. v$sql_plan查询filter_predicates字段包含TO_NUMBER、SYS_OP_C2C、INTERNAL_FUNCTION谓词的,且options和operation存在TABLE ACCESS FULL的,例如,

代码语言:javascript
代码运行次数:0
运行
复制
SELECT *
  FROM V$SQL_PLAN X
 WHERE (X.FILTER_PREDICATES LIKE '%INTERNAL_FUNCTION%'
    OR X.FILTER_PREDICATES LIKE '%SYS_OP_C2C%')
   AND x.object_owner = 'BD_ADMIN'
   AND options = 'FULL'
   AND operation = 'TABLE ACCESS';

2. 解析函数中的列字段名称,如果该字段在dba_ind_columns存在,说明该字段是索引字段,但是执行计划用的全表扫描,说明这条SQL存在可能受了隐式转换的影响。

但这有几个问题,

1. 步骤1中存在一个难点,就是怎么知道这几个函数是在=左边,因为如果在右边,其实不会产生什么影响。另外函数中就一定是字段名称?

2. 以上的逻辑,一些“常规”的隐式转换问题,应该能找到,但总觉得存在一些漏洞,应该不能穷举出所有的场景。

3. 如果从隐式转换,推进一下,就是索引列使用了函数运算,这个可能就很多种场景了,例如用了TO_CHAR、TRUNC、UPPER、LOWER这些,但是肯定不够,更不要说+、-、*、/这些运算符,穷举有些困难,如果验证这个,确实不太合适,是否有更通用的验证逻辑?

基于这个需求,

1. 隐式转换导致索引不能使用的SQL。

2. 索引列使用函数运算的SQL。

还想请教一下各位大佬,有无更合适、靠谱、通用的方式和逻辑,能找出这两个场景的SQL?

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/05/10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档