Tuesday, October 12, 2010

At which situation IN is better than EXIST ?



Well, the two are processed very differently

Select * from T1 where x in ( select y from T2 )

is typically processed as:

select * 
  from t1, ( select distinct y from t2 ) t2
 where t1.x = t2.y;

Sub query is evaluated, distinct'ed, indexed (or hashed or sorted) and then joined to the original table - typically.

As opposed to:

select * from t1 where exists (select null from t2 where y = x)

That is processed more like:

   for x in (select * from t1)
   loop
      if (exists (select null from t2 where y = x.x)
      then 
         OUTPUT THE RECORD
      end if
   end loop

It always results in a full scan of T1 whereas the first query can make use of an index on T1(x).

So, when is where exists appropriate and in appropriate?  Lets say the result of the sub query:

    (select y from T2)

is "huge" and takes a long time.  But the table T1 is relatively small and executing ( select null from t2 where y = x.x ) is very very fast (nice index on t2(y)).  Then the exists will be faster as the time to full scan T1 and do the index probe into T2 could be less then the time to simply full scan T2 to build the subquery we need to distinct on.

Let’s say the result of the sub query is small -- then IN is typically more appropriate.

If both the sub query and the outer table are huge -- either might work as well as the other -- depends on the indexes and other factors.

The ROT (rule of thumb) here is :

BIG outer query and SMALL inner query = IN. SMALL outer query and BIG inner query = WHERE EXISTS. 

Monday, October 4, 2010

How to Troubleshoot Distributed Transactions ? (ORA-2019, ORA-2058, ORA-2068, ORA-2050, FAILED DISTRIBUTED TRANSACTIONS)


How to Troubleshoot Distributed Transactions ? 

Database "A" has init.ora parameter 
db_domain incorrectly specified as ".WORLD", that causes the init.ora parameter "service_names" to be "A..WORLD". 

A select from GLOBAL_NAMES shows "A.WORLD". Database "B" has init.ora parameters of "db_domain=WORLD" and SERVICE_NAMES=B.WORLD". 

Select from GLOBAL_NAME shows "B.WORLD". The table synonyms referring to the remote tables work for both databases to data manipulation. But, the synonyms on database "A" cannot be used to describe the tables on "B" (ORA-02019). 

Can I safely change the "A" init.ora parameter from "db_domain=.WORLD" to "db_domain=WORLD"? I know from my test databases that that parameter inhibits the describe. 

Set GLOBAL_NAMES=FALSE in the init.ora and restart the database.

The syntax is as follows: 
Create public database link  
Connect to uid identified by pw 
Using 'alias'; 

Ensure that global_names = true in the destination server's init.ora file. If the global name = true parameter is set in the init.ora, check the value of the db_name and db_domain parameters in that same init.ora file. Log into the destination server via sqlplus and do a SELECT * FROM GLOBAL_NAME. This value should match the db_name specified in the init.ora file. If the global name = true parameter exists in the init.ora file, then the name of the dblink must be either that databases sid or global dbname.