oracle游标数据无法打开
2022-08-08 23:59:25
  1. 问题出现
    查询接口超时,数据来自oracle存储过程。其中一个存储过程查询数量,另外一个存储过程查询分页数据。
  2. 查找问题
    通过plsql工具测试存储过程后,发现查询数量的函数正常返回结果,响应速度快,查询分页数据的函数正常返回,响应速度快。打开游标plsql卡住未响应。
  3. 定位问题
  • 将完整带条件的sql语句拿出执行成功查处结果,响应速度快。
  • 测试数据库中其他返回游标的存储过程,正常返回,并且能打开游标展示数据。
  • 创建一个新的存储过程使用原有SQL,测试后存在相同问题,为了不影响生产环境,接着可以使用这个新的存储过程做测试。
  • 查看数据库进程,发现此存储过程的SQL在多个应用实例里执行并且等待结束,杀掉这些进程后,依然未解决问题。
  • 将能在正常查询窗口中执行的SQL语句放进存储过程中,测试,游标能够正常打开展示数据。
  • 逐步排查每个动态的参数,发现SQL中有个逻辑判断当前入参是否为空。举例:如果参数为空的情况 (0 = 1 or user_name = nvl(?,’’)),如果参数不为空的情况(1 = 1 or user_name = nvl(?, ‘’))。问题就出在当参数不为空时会执行 1 = 1 为true,后面会继续执行user_name = nvl(?, ‘’)。
  1. 问题解决
    不太清楚游标里面这样执行为什么会执行不出来,在正常的SQL查询中是能够正常执行,并且执行结果很快。这里查看了其他存储过程中的写法,其他写法是通过在游标外面先定义一个字符串用来拼接SQL,并且在外面处理逻辑。例如:

    1
    2
    3
    if (user_name is not null) then
    order_sql := order_sql ||' user_name='''|| user_name || '''';
    end;

    通过这种sql拼接的方式,逐个判断参数是否为空。最后放入游标中:

    1
    open cursor for order_sql;

    ps:原来的写法:

    1
    2
    open cursor for 
    select * from table_a where (flag = 0 or user_name = nvl(userName,''));

    最后通过测试,解决问题。

  2. 结束
    虽然还不清楚具体是什么原因导致的,但是根据原SQL中存在 1 = 1这样的条件以及or关键字的存在,猜测是游标中执行查询SQL时会全表扫描,表中数据量逐渐增大导致了之前正常的功能直到现在才暴露出来。

上一页
2022-08-08 23:59:25
下一页