如何找到隐式转换的SQL?

Posted bisal

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何找到隐式转换的SQL?相关的知识,希望对你有一定的参考价值。

隐式转换相关的文章,

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

浅谈显式转换和隐式转换

隐式转换的案例场景

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

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

场景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,

SQL> select * from t1 where col in ('A','B','C') and id=1;
        ID COL
---------- ---------------
         1 A

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

--------------------------------------------------------------------------
| 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,

--------------------------------------------------------------------------
| 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的,例如,

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?

近期更新的文章:

为什么日期不建议使用VARCHAR2或者NUMBER?

查看时间戳类型的绑定变量

写代码如何事半功倍?

支持超过4000字节的varchar2类型

“自以为对的”MyBatis空闲连接探测的机制

小白学习MySQL - 索引键长度限制的问题

创建主键的三种方式对指定索引表空间操作的纠正

Oracle优化器的“短路”

小白学习MySQL - MySQL会不会受到“高水位”的影响?

MySQL行转列的小需求

Oracle的greatest和least函数

我的股市生涯

Oracle创建主键的三种方式

非Oracle Linux下Oracle 19c CDB数据库安装

小白学习MySQL - 数据库软件和初始化安装

小白学习MySQL - 闲聊聊

Redis和Sentinel的安装部署和配置

“火线”和“零线”

通过索引提升SQL性能案例一则

如何手动添加jar包到maven本地库?

1元股权转让的一点思考

如何打造一个经常宕机的业务系统?

Linux恢复误删文件的操作

Oracle处理IN的几种方式

如何搭建一支拖垮公司的技术团队?

IP地址解析的规则

MySQL的skip-grant-tables

国产数据库不平凡的一年

Oracle要求顺序的top数据检索问题

了解一下sqlhc

Oracle的MD5函数介绍

Oracle 19c的examples静默安装

sqlplus登录缓慢的解决

VMWare 11安装RedHat Linux 7过程中碰到的坑

COST值相同?是真是假?

Oracle 11g的examples静默安装

文章分类和索引:

公众号700篇文章分类和索引

以上是关于如何找到隐式转换的SQL?的主要内容,如果未能解决你的问题,请参考以下文章

隐式转换的替代方案不是万能的

sql 日期转换代码片段 - Dato,120,konvertere

深入浅出JavaScript中的隐式转换

SQL Server有意思的数据类型隐式转换问题

SQL SERVER中隐式转换的一些细节浅析

SQL优化案例:隐式转换