案例:troubleshooting ORA-01722 from Queries with Dependent Predicates

本案例来自西区某客户,应用反应某条sql好几年都运行正常,最近经常会出现ORA-01722错误。

该错误通常发生在类型转换时遇到非法数字,如:

按道理该错误应该非常容易诊断,肯定是表中字符类型的字段上存在非法数字导致的,但是应用非常坚持的认为该sql一直运行正常,那么我们就来看看吧。

报错很明显,问题出在ON D.LOAN_BATCH = NVL(REPLACE(B.LEASE_TIME, ‘投放日’, ”), 1) – 1上,其中LOAN_BATCH为number类型,LEASE_TIME为varchar2类型,熟悉隐式转换规则的话,肯定知道该连接条件会被CBO改写D.LOAN_BATCH=TO_NUMBER(NVL(REPLACE(B.LEASE_TIME,’投放日’,”),’1′))-1,那么问题肯定出在LEASE_TIME上。B是一个inline view的别名,该字段来自于表YLS_INOUT_PLAN_C

通过该sql检测结果集输出确实是正常的,但是YLS_INOUT_PLAN_C的LEASE_TIME除了”投放日“之外还存在其他中文字符,之所以上面的结果集能正常是因为业务逻辑上yls_event_type的谓词EVENT_CODE IN (‘10101’, ‘10102’)过滤后再关联YLS_INOUT_PLAN_C可以保证过滤掉除了”投放日“之外的其他中文字符。

那么就存在一种可能,当inline view发生view merge时,会得到更多的表驱动顺序。这也是查询转换的意义所在,其执行计划如果选择是YLS_INOUT_PLAN_C直接与yls_LEASE_LOAN_PLAN_C关联时,就会报出ORA-01722。

从执行计划中可以看到,inline view发生了view merge,并且还发生了hash join的SWAP_JOIN_INPUTS,使得执行计划为:

这样在谓词13 – access(“D”.”LOAN_BATCH”=TO_NUMBER(NVL(REPLACE(“YI”.”LEASE_TIME”,’投放日’,”),’1′))-1连接时就会出现ORA-01722,这种现象mos有一篇文档说明ORA-01722, ORA-01839, ORA-01841, ORA-01847 or ORA-01858 from Queries with Dependent Predicates (Doc ID 232243.1)

解决方法也很简单,使用no_merge不让inline view发生view merge即可,或者在inline view中加入rownum伪列,当inline view中出现rownum也是不能做view merge的,该sql的inline view改写如下:

当然这种sql写法本身也是不严谨的,虽然业务逻辑是没有问题的,但是太依赖于执行计划的表驱动顺序,所以在sql开发中特别是遇到类型转换时,需要注意这种情况。

模拟该案例也非常简单,test demo如下:

 

 

 

此条目发表在Oracle, Oracle troubleshooting分类目录,贴了标签。将固定链接加入收藏夹。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注