Avoid using sub-selects and redundant expressions | Other important SQL tuning hints


IN versus Exists

To quote the Oracle Tuning Reference, "In certain circumstances, it is better to use IN rather than EXISTS. In general, if the selective predicate is in the subquery, then use IN. If the selective predicate is in the parent query, then use EXISTS."

IN and EXISTS work very differently. In case of IN, the subquery is executed first and then the result is compared with the outer table. The EXISTS clause, however, is evaluated for every value in the outer table. Here is an example for WebSphere Commerce that shows that EXISTS performs much better than IN when the selective predicate is the parent query. The query below was written using IN, and it was running for a long time. According the above role, the query is a good candidate to use EXISTS instead of IN. The selective predicates (T2.REGISTERTYPE IN ('R') AND mr1.ROLE_ID = -29) are in the parent query.

SELECT DISTINCT t1.state, t1.member_id, t1.optcounter, t1.type, 
t2.field2, t2.registrationupdate, t2.field3, t2.lastorder, 
t2.language_id, t2.prevlastsession, t2.setccurr, t2.dn, 
t2.registrationcancel, t2.lastsession, t2.registration, t2.field1, 
t2.registertype, t2.profiletype 
FROM userreg, mbrrole mr1 , users t2, member t1
WHERE             
        t2.registertype IN ('R') 
        AND mr1.role_id = -29 
        AND (EXISTS
              ( SELECT 1 
                FROM mbrrel mr, mbrrole ml 
                WHERE (
                         (mr.descendant_id = -1000 
                             AND mr.sequence=1 
                             AND mr1.orgentity_id = mr.ancestor_id) 
                         OR 
                         (ml.role_id IN (-1,-20,-27) 
                             AND ml.member_id = -1000 
                             AND mr1.orgentity_id = ml.orgentity_id) 
             OR 
             ( 
                             (ml.role_id IN (-1,-20,-27) 
                                 AND ml.member_id = -1000 
                                 AND mr.ancestor_id = ml.orgentity_id ) 
                             AND mr1.orgentity_id = mr.descendant_id)
                         )
                ) 
                OR mr1.orgentity_id IN
                   (SELECT ancestor_id 
                    FROM mbrrel mrl, mbrrole mble 
                    WHERE mble.member_id=-1000
                          AND mble.role_id IN  (-1,-20,-27) 
                          AND mrl.descendant_id = mble.orgentity_id
                   ) 
        )
        AND t2.users_id = mr1.member_id 
        AND userreg.users_id = t2.users_id 
        AND t1.member_id = t2.users_id 
        AND t1.type = 'u'