如何找到隐式转换的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?
近期更新的文章:
《小白学习MySQL - MySQL会不会受到“高水位”的影响?》
《我的股市生涯》
《非Oracle Linux下Oracle 19c CDB数据库安装》
《VMWare 11安装RedHat Linux 7过程中碰到的坑》
文章分类和索引:
以上是关于如何找到隐式转换的SQL?的主要内容,如果未能解决你的问题,请参考以下文章