前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >隐式数据类型转换案例一则

隐式数据类型转换案例一则

作者头像
老虎刘
发布2022-06-22 17:32:51
4180
发布2022-06-22 17:32:51
举报
文章被收录于专栏:老虎刘谈oracle性能优化

在OLTP系统中,要求对频繁执行的SQL使用绑定变量(唯一值少的字段,如type、status等,数据分布不均是常见情况,这种字段不建议使用绑定变量)。

在使用绑定变量时,有时开发人员对使用的字段类型不是很清楚,比如银行账号、电话号码、全数字型的序列号等,可以定义成number类型,也可以定义成varchar2类型。如果字段类型与绑定变量使用的数据类型不匹配,就会发生隐式类型转换。

常见的有害隐式类型转换发生在下面情况:varchar2_col = :number_variable

即varchar2类型的字段,使用的绑定变量类型是number类型,这将造成字段上的索引不能使用,如果是频繁执行的SQL,将会给系统带来严重的性能问题。

下面是一个比较让人迷惑的案例:

在对某客户一个重要系统进行优化时,在AWR的TOP SQL中遇到了这个SQL:

SQL代码非常简单:

SELECT NVL(MAX(DCC_PROC_ID),0)

FROM P_SERV A

WHERE ACC_NBR = :B2 AND SERV_ID <> :B1;

其中ACC_NBR(varchar2类型)和SERV_ID都是选择性很好的字段,两个字段上都有索引,因为SERV_ID是不等于条件,不能使用索引,那么这个SQL正常情况应该是使用ACC_NBR字段上的索引才是最佳路径。而且平均执行时间不应该超过1毫秒,实际显示平均执行时间达到了540毫秒,肯定有问题。

通过sqlhc工具收集了该SQL相关信息,发现SQL的执行计划有3个:

其中1最好,2和3都与1差了几百倍的性能。而根据常理,只有执行计划1才是比较正常的性能表现。

再看SQL执行情况,1和2两个计划同时存在,效率差别非常明显:

再来分别看3个执行计划的具体内容:

执行计划1,plan_hash_value=1228755719,使用了ACC_NBR字段上的索引,没有问题。

执行计划2,plan_hash_value=164228054,使用全表扫描的执行计划,在执行计划显示的最后部分,Predicate Information里,有TO_NUMBER(“ACC_NBR”)=:B2 字样,再结合上面部分的Peeked Binds信息,ACC_NBR字段使用的绑定变量是NUMBER类型,由此可以判断,这是因为绑定变量使用的数据类型与字段本身的类型不匹配,优化器自动对字段做了隐式类型转换,相当于在字段上使用了TO_NUMBER函数,这种情况就不能使用ACC_NBR字段上的索引:

再来看第3个执行计划,plan_hash_value=1669185283,这个执行计划因为是历史执行计划,看不到Predicate Information信息(只有sql执行计划存在于V$SQL_PLAN视图时,才会有Predicate Information信息,DBA_HIST_SQL_PLAN不保存这个信息),但是绑定变量使用的数据类型能够看到,是NUMBER类型。这种情况下,优化器还是因为隐式类型转换不能使用ACC_NBR字段上的索引,转而使用两个索引全扫描再做index join的执行计划,效率更差。

经过开发人员对代码的核对,发现这段SQL在两个不同的代码段中被调用,一段代码使用了正确的绑定变量类型(varchar2),而另一段则使用了number类型的绑定变量,这就造成了同一个sql_id, 同时存在多个不同执行计划的情况。这种情况应该属于应用代码不规范。

研发人员将使用number类型的绑定变量更换成varchar2类型后,SQL就都使用执行计划1了,执行效率大幅提高,CPU使用率也下降很多。

有的DBA在遇到这种多个执行计划同时存在的情况(这个情况比较特殊),可能会考虑使用SQL profile来固定执行计划,但是固定的执行计划只对正确使用绑定变量类型的SQL生效,对于不正确绑定变量类型,SQL profile也不起作用。

总结:

研发人员在使用绑定变量时,应该密切关注表字段定义的数据类型,尤其是当电话号码、账号信息等全数字的字段定义成varchar2时,千万不要使用number类型的绑定变量,否则会严重消耗系统资源,SQL本身性能也会非常差。

另一种情况是number数据类型的字段,在绑定变量是varchar2时,也会发生隐式类型转换。但是,这个隐式类型转换是发生在绑定变量上,因此不会对执行计划有影响,是无害的。

如何检查和发现系统中存在的隐式类型转换? 这里简单列出最常见的一种检查方法:

select sql_id,object_owner,operation,options,object_name,

filter_predicates,projection

from v$sql_plan where filter_predicates like 'TO_NUMBER%'

此外还有一些其他的隐式类型转换,如date类型的字段,使用了timestamp的绑定变量等,也需要注意。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-07-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老虎刘谈oracle性能优化 微信公众号,前往查看

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

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

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