Wednesday, June 6, 2012

DB2 ( + Join operator used along with NVL operator)

Recently I came across an issue with usage of + operator(Basically Right Outer Join in my case) along with NVL .
Basically when we use NVL , DB2 internally uses COALESCE function (We can make it out by looking at explain plan).
But when it is used along with + Join operator , the explain plan shows that NVL function is internally not able to call COALESCE function.
Example :
--------------------------------------------------------------------------------
Original Query in Oracle ( Which does not give required output in DB2
--------------------------------------------------------------------------------
           select  rps_obj.object_name, rps_rel.CHILD_OBJ_ID, NVL(rps_rel.CHILD_OBJ_ID, 0), rps_rel.PARENT_OBJ_ID, NVL(rps_rel.PARENT_OBJ_ID, 0), rps_res.OBJECT_ID
      from RPS_OBJECTS          rps_obj,
           (select * from RPS_OBJ_DEPENDENCIES where DEPENDS_ON in (select OBJECT_ID from RPS_OBJECTS where OBJECT_CATEGORY = 'Compliance Objects')) rps_dpnd_res,
           RPS_RESOURCE_OBJECTS rps_res,
           RPS_OBJECTS          rps_obj_res,
           ASSETTYPES           at,
           (select * from RPS_OBJ_DEPENDENCIES where DEPENDS_ON in (select OBJECT_ID from RPS_OBJECTS where OBJECT_CATEGORY = 'Compliance Object Relations')) rps_dpnd_rel,         
           RPS_RELATIONS        rps_rel,
           RPS_OBJECTS          rps_obj_rel
     where rps_obj.OBJECT_CATEGORY = 'Compliance Object Views'
       and rps_obj.OBJECT_TYPE = 'VIEW'
       and rps_obj.OBJECT_ID = NVL(38, rps_obj.OBJECT_ID)
       and rps_dpnd_res.OBJECT_ID = rps_obj.OBJECT_ID
       and rps_res.OBJECT_ID = rps_dpnd_res.DEPENDS_ON
       and rps_obj_res.OBJECT_ID = rps_res.OBJECT_ID and rps_obj_res.OBJECT_CATEGORY = 'Compliance Objects'
       and at.ASSETTYPEID = rps_res.CONTENT_TYPE
       and rps_dpnd_rel.OBJECT_ID (+) = rps_obj.OBJECT_ID
       and rps_rel.OBJECT_ID (+) = rps_dpnd_rel.DEPENDS_ON
       and rps_obj_rel.OBJECT_ID (+) = rps_rel.OBJECT_ID and rps_obj_rel.OBJECT_CATEGORY (+) = 'Compliance Object Relations'
        and NVL(rps_rel.CHILD_OBJ_ID, 0) = NVL(rps_rel.PARENT_OBJ_ID, 0)
       and NVL(rps_rel.CHILD_OBJ_ID, rps_res.OBJECT_ID) = rps_res.OBJECT_ID
-------------------------------------------------------------------------------------------------
There are two possible solution to this
-------------------------------------------------------------------------------------------------
Solution 1 ) Simplify the NVL function.
Change the following piece of code
        and NVL(rps_rel.CHILD_OBJ_ID, 0) = NVL(rps_rel.PARENT_OBJ_ID, 0)
       and NVL(rps_rel.CHILD_OBJ_ID, rps_res.OBJECT_ID) = rps_res.OBJECT_ID
To following :
    --  and (rps_rel.CHILD_OBJ_ID = rps_rel.PARENT_OBJ_ID or (rps_rel.CHILD_OBJ_ID is NULL and rps_rel.PARENT_OBJ_ID is NULL))
     -- and (rps_rel.CHILD_OBJ_ID is NULL or rps_rel.CHILD_OBJ_ID = rps_res.OBJECT_ID)
------------------------------------------------------------------------------------------------------------------------------
Solution 2 : Rewrite the complete query following ANSI standard
------------------------------------------------------------------------------------------------------------------------------
Modified query :
      select  rps_obj.object_name, rps_rel.CHILD_OBJ_ID, NVL(rps_rel.CHILD_OBJ_ID, 0), rps_rel.PARENT_OBJ_ID, NVL(rps_rel.PARENT_OBJ_ID, 0), rps_res.OBJECT_ID
      from  RPS_RESOURCE_OBJECTS rps_res, RPS_OBJECTS  rps_obj_res, ASSETTYPES at,
      (select * from RPS_OBJ_DEPENDENCIES where DEPENDS_ON in (select OBJECT_ID from RPS_OBJECTS where OBJECT_CATEGORY = 'Compliance Objects')) rps_dpnd_res,
      RPS_OBJECTS rps_obj_rel RIGHT OUTER JOIN RPS_RELATIONS rps_rel ON rps_obj_rel.OBJECT_ID = rps_rel.OBJECT_ID AND rps_obj_rel.OBJECT_CATEGORY  = 'Compliance Object Relations'
      RIGHT OUTER JOIN (select * from RPS_OBJ_DEPENDENCIES where DEPENDS_ON in (select OBJECT_ID from RPS_OBJECTS where OBJECT_CATEGORY = 'Compliance Object Relations')) rps_dpnd_rel ON rps_rel.OBJECT_ID = rps_dpnd_rel.DEPENDS_ON
       RIGHT OUTER JOIN RPS_OBJECTS rps_obj ON rps_dpnd_rel.OBJECT_ID = rps_obj.OBJECT_ID
            where rps_obj.OBJECT_CATEGORY = 'Compliance Object Views'
       and rps_obj.OBJECT_TYPE = 'VIEW'
       and rps_obj.OBJECT_ID = NVL(38, rps_obj.OBJECT_ID)
       and rps_dpnd_res.OBJECT_ID = rps_obj.OBJECT_ID
       and rps_res.OBJECT_ID = rps_dpnd_res.DEPENDS_ON
       and rps_obj_res.OBJECT_ID = rps_res.OBJECT_ID and rps_obj_res.OBJECT_CATEGORY = 'Compliance Objects'
       and at.ASSETTYPEID = rps_res.CONTENT_TYPE
       and NVL(rps_rel.CHILD_OBJ_ID, 0) = NVL(rps_rel.PARENT_OBJ_ID, 0)
      and NVL(rps_rel.CHILD_OBJ_ID, rps_res.OBJECT_ID) = rps_res.OBJECT_ID

Note : This issue has been fixed in v97fp6 now. So upgrade your instance to v97fp6

No comments:

Post a Comment