Home » RDBMS Server » Performance Tuning » Driving Table in Oracle 9i
Driving Table in Oracle 9i [message #170424] Wed, 03 May 2006 13:28 Go to next message
kumarsz
Messages: 180
Registered: March 2005
Location: canada
Senior Member
Hi,
i am using "Oracle9i Enterprise Edition Release 9.0.1.1.1"

attached herewith is a file which has a query written with changing a table sequence and its Explain Plans.

i was assuming was that, if both tables are having indexes on joining column and if i am changing sequence of table in FROM clause the driving table shall go for FTS and inner table for index scan.

however in the results shown inspite of the fact that Dept table is using index "Table Access Full" is not understood by me.

also the Nested Loop position is changed.
Please guide me about this

Note : i have taken statistics (incl histograms) and ran the query 3-4 times for the Explain Plans.

Thanks in advance
Pratap
Re: Driving Table in Oracle 9i [message #170435 is a reply to message #170424] Wed, 03 May 2006 17:24 Go to previous messageGo to next message
Mahesh Rajendran
Messages: 10707
Registered: March 2002
Location: oracleDocoVille
Senior Member
Account Moderator
May i assume that your OPTIMIZER_INDEX_CACHING value is still left in its default value? Can you afford to change it to 90 and test again?

Meanwhile, if this the default EMP/DEPT table and you have collected proper statistcs , it is supposed to do a hash join. Again, it all depends on data distribution. Those demo tables in 9i with all the default settings will use Hash join.

Re: Driving Table in Oracle 9i [message #170670 is a reply to message #170424] Thu, 04 May 2006 13:46 Go to previous messageGo to next message
kumarsz
Messages: 180
Registered: March 2005
Location: canada
Senior Member
Hi Mahesh,
now i have tried with following table structure and queries where i am getting suprising results
when index is only on 1 table FTS is occurring for 1 table.
when i create index on another table also (involved in join) both tables are FTS in the Explain plan
also driving table has no effect inspite of equal ranked index.

(Note :regarding optmizer_index_caching i will try today, but can you brief it here about it)

Please guide me on following result, i am trying to understand only a single join query plan for a long time, please help me understand it why it takes hash sometimes why sometimes Nested loop.


Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-2000 Microsoft Corp.

C:\>sqlplus

SQL*Plus: Release 9.0.1.0.1 - Production on Thu May 4 23:49:02 2006

(c) Copyright 2001 Oracle Corporation.  All rights reserved.

Enter user-name: scott/[email]tiger@db02.world[/email]

Connected to:
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production

create table objects as select * from dba_objects;
create table objects1 as select * from dba_objects;
update objects1 set object_id = 17287 where rownum<150;

update objects1 set object_id = 7559 where rownum<150 and object_id <>  17287;

update objects1 set object_id = 22543 where rownum<150 and object_id <>  17287 and object_id <> 7559;

update objects1 set object_id = 13615 where rownum<150 and object_id <>  17287 and object_id <> 7559 and object_id <> 22543;

update objects1 set object_id = 10173 where  object_id <>  17287 and object_id <> 7559 and object_id <> 22543 and object_id <> 13615;
commit;
alter table objects add constraint pk_objects primary key(object_id);
alter table objects1 add constraint fk_objects1 foreign key(object_id) references objects(object_id)

analyze tables / indexes comput statistics 
******************************************

SQL> set autotrace traceonly
SQL> select o.object_name,o1.owner from objects o, objects1 o1 where o.object_id = o1.object_id;

30058 rows selected.


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   NESTED LOOPS
   2    1     TABLE ACCESS (FULL) OF 'OBJECTS1'
   3    1     TABLE ACCESS (BY INDEX ROWID) OF 'OBJECTS'
   4    3       INDEX (UNIQUE SCAN) OF 'PK_OBJECTS' (UNIQUE)




Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      64515  consistent gets
          0  physical reads
          0  redo size
     814299  bytes sent via SQL*Net to client
     262888  bytes received via SQL*Net from client
       2005  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      30058  rows processed

SQL> select o.object_name,o1.owner from objects o1, objects1 o where o.object_id = o1.object_id;

30058 rows selected.


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   NESTED LOOPS
   2    1     TABLE ACCESS (FULL) OF 'OBJECTS1'
   3    1     TABLE ACCESS (BY INDEX ROWID) OF 'OBJECTS'
   4    3       INDEX (UNIQUE SCAN) OF 'PK_OBJECTS' (UNIQUE)




Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      64515  consistent gets
          0  physical reads
          0  redo size
    1632112  bytes sent via SQL*Net to client
     262888  bytes received via SQL*Net from client
       2005  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      30058  rows processed

SQL> create index fk_objects1 on objects1(object_id);

Index created.
Analyze tables / indexes 

SQL> select o.object_name,o1.owner from objects o, objects1 o1 where o.object_id = o1.object_id;

30058 rows selected.


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=185 Card=30058 Bytes
          =3276322)

   1    0   HASH JOIN (Cost=185 Card=30058 Bytes=3276322)
   2    1     TABLE ACCESS (FULL) OF 'OBJECTS1' (Cost=43 Card=30058 By
          tes=901740)

   3    1     TABLE ACCESS (FULL) OF 'OBJECTS' (Cost=43 Card=30057 Byt
          es=2374503)





Statistics
----------------------------------------------------------
         42  recursive calls
          2  db block gets
        837  consistent gets
         16  physical reads
          0  redo size
     814307  bytes sent via SQL*Net to client
     262888  bytes received via SQL*Net from client
       2005  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      30058  rows processed

SQL> select o.object_name,o1.owner from objects o1, objects1 o where o.object_id = o1.object_id;

30058 rows selected.


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=185 Card=30058 Bytes
          =3276322)

   1    0   HASH JOIN (Cost=185 Card=30058 Bytes=3276322)
   2    1     TABLE ACCESS (FULL) OF 'OBJECTS' (Cost=43 Card=30057 Byt
          es=901710)

   3    1     TABLE ACCESS (FULL) OF 'OBJECTS1' (Cost=43 Card=30058 By
          tes=2374582)





Statistics
----------------------------------------------------------
         42  recursive calls
          0  db block gets
       2784  consistent gets
         63  physical reads
          0  redo size
    1632112  bytes sent via SQL*Net to client
     262888  bytes received via SQL*Net from client
       2005  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      30058  rows processed


Thanks in Advance,
Pratap

[Updated on: Thu, 04 May 2006 16:20] by Moderator

Report message to a moderator

Re: Driving Table in Oracle 9i [message #170708 is a reply to message #170670] Thu, 04 May 2006 20:06 Go to previous messageGo to next message
Mahesh Rajendran
Messages: 10707
Registered: March 2002
Location: oracleDocoVille
Senior Member
Account Moderator
Talking about your testcase, CBO is doing exactly what needs to be done.
Once you add proper indexes and analyzed(statistics and histograms) both tables/indexes,
both the queries go for HASH JOIN as i said in earlier post.

Talking about Joins, there are basically 3 types.
Hash Joins,sort-merge and nested loops (which ***may***produce two different plans using unique scans or range scan)

I am taking the regular EMP/DEPT tables and tweaking them in this session.
As usual,proper statistics along with histograms are *****always**** very important.

In your case, i suspect whether you have collected any statistics at all (where it produces the nested loop),because i am not seeing any statistics!!.
Or You may have collected statistics but NO HISTOGRAMS, so the CBO might be hallucinating.

--
-- I am setting up my environment
-- Just regular emp/dept tables. I modified the deptno number(2) to deptno number
--
scott@9i > get emp_loopinsert
  1   begin
  2   for mag in 1..15 loop
  3       insert into emp (select * from emp);
  4   end loop;
  5   commit;
  6*  end;
scott@9i > /

PL/SQL procedure successfully completed.

scott@9i > get dept_loopinsert
  1   begin
  2   for mag in 1..15 loop
  3       insert into dept (select * from dept);
  4   end loop;
  5   commit;
  6*  end;
scott@9i > /

PL/SQL procedure successfully completed.

scott@9i > update dept set deptno=rownum;

131072 rows updated.

scott@9i > commit;

Commit complete.

scott@9i > alter table dept add constraint pk_deptno primary key (deptno);

Table altered.

--
-- What you might have done is
--
scott@9i > analyze table dept compute statistics for all columns for all indexes;

Table analyzed.

scott@9i > analyze table emp compute statistics for all columns for all indexes;

Table analyzed.

scott@9i > set autotrace traceonly exp;
scott@9i > select E.empno,D.dname from emp E, dept D where e.deptno=d.deptno;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   NESTED LOOPS
   2    1     TABLE ACCESS (FULL) OF 'EMP'
   3    1     TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'
   4    3       INDEX (UNIQUE SCAN) OF 'PK_DEPTNO' (UNIQUE)

--
-- Now let us create the second index, you were talking about.
-- Now, you can see the other nested loop plan that uses a RANGE SCAN.
--

  1* create index index_deptno on emp(deptno)
scott@9i > /

Index created.

scott@9i > analyze table dept compute statistics for all columns for all indexes;

Table analyzed.

scott@9i > analyze table emp compute statistics for all columns for all indexes;

Table analyzed.

scott@9i > select E.empno,D.dname from emp E, dept D where e.deptno=d.deptno;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
   2    1     NESTED LOOPS
   3    2       TABLE ACCESS (FULL) OF 'DEPT'
   4    2       INDEX (RANGE SCAN) OF 'INDEX_DEPTNO' (NON-UNIQUE)

--
-- What you should have done is
--
scott@9i > get gather_table_stats
  1* exec dbms_stats.gather_table_stats('SCOTT',upper('&TABLE_NAME'),METHOD_OPT=>'For all indexed columns size 250',CASCADE=>true);
scott@9i > @gather_table_stats
Enter value for table_name: EMP

PL/SQL procedure successfully completed.

scott@9i > @gather_table_stats
Enter value for table_name: DEPT

PL/SQL procedure successfully completed.

scott@9i > select E.empno,D.dname from emp E, dept D where e.deptno=d.deptno;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=801 Card=458752 Byte
          s=9633792)

   1    0   HASH JOIN (Cost=801 Card=458752 Bytes=9633792)
   2    1     TABLE ACCESS (FULL) OF 'DEPT' (Cost=49 Card=131072 Bytes
          =1835008)

   3    1     TABLE ACCESS (FULL) OF 'EMP' (Cost=261 Card=458752 Bytes
          =3211264)

/*
--
-- So with a Nested loop, for each row in the driving table you search an
-- equal value in the other table.
-- In Hash Join, you using the smaller table , hash it and probe the Bigger table.
-- You can see from the Card, DEPT is the smaller table that is hashed.
-- Let us cross-check that Card and play with the statistics see whether it holds true.
--
*/
scott@9i > set autotrace off;
scott@9i > select table_name,num_rows from user_tables where table_name in ('EMP','DEPT');

TABLE_NAME                       NUM_ROWS
------------------------------ ----------
DEPT                               131072
EMP                                458752

scott@9i > exec dbms_stats.set_table_stats('SCOTT','EMP',numrows=>100);

PL/SQL procedure successfully completed.

/*
-- let us trick the CBO. Now CBO thinks EMP has only 100 records.
-- When running the same query, driving table is changed.
*/

scott@9i > select table_name,num_rows from user_tables where table_name in ('EMP','DEPT');

TABLE_NAME                       NUM_ROWS
------------------------------ ----------
DEPT                               131072
EMP                                   100

scott@9i > set autotrace traceonly exp
scott@9i > select E.empno,D.dname from emp E, dept D where e.deptno=d.deptno;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=312 Card=100 Bytes=2
          100)

   1    0   HASH JOIN (Cost=312 Card=100 Bytes=2100)
   2    1     TABLE ACCESS (FULL) OF 'EMP' (Cost=261 Card=100 Bytes=70
          0)

   3    1     TABLE ACCESS (FULL) OF 'DEPT' (Cost=49 Card=131072 Bytes

/*
-- Now What is up with this SortMerge Join?
-- here Both the tables are sorted first and then Merged
-- This will typicall occurs when Both the involved tables are massively large
-- So let us tweak the stats again.
*/
scott@9i > @gather_table_stats
Enter value for table_name: EMP

PL/SQL procedure successfully completed.

scott@9i > @gather_table_stats
Enter value for table_name: dept

PL/SQL procedure successfully completed.

scott@9i > set autotrace off;
scott@9i > select table_name,num_rows from user_tables where table_name in ('DEPT','EMP');

TABLE_NAME                       NUM_ROWS
------------------------------ ----------
DEPT                               131072
EMP                                458752

scott@9i >  exec dbms_stats.set_table_stats('SCOTT','DEPT',numrows=>100000000);

PL/SQL procedure successfully completed.

scott@9i > set autotrace traceonly exp
scott@9i > select E.empno,D.dname from emp E, dept D where e.deptno=d.deptno;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=3768 Card=350000000
          Bytes=7350000000)

   1    0   MERGE JOIN (Cost=3768 Card=350000000 Bytes=7350000000)
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'DEPT' (Cost=726 Card=1
          00000000 Bytes=1400000000)

   3    2       INDEX (FULL SCAN) OF 'PK_DEPTNO' (UNIQUE) (Cost=274 Ca
          rd=100000000)

   4    1     SORT (JOIN) (Cost=3042 Card=458752 Bytes=3211264)
   5    4       TABLE ACCESS (FULL) OF 'EMP' (Cost=261 Card=458752 Byt
          es=3211264)









Re: Driving Table in Oracle 9i [message #170874 is a reply to message #170424] Fri, 05 May 2006 12:02 Go to previous messageGo to next message
kumarsz
Messages: 180
Registered: March 2005
Location: canada
Senior Member
Hi Mahesh,
Your analysis and further help is simply amazing!! no words for it.
attached herewith a file where i have taken EXPLAIN PLAN for queries on different server (this i have tried in my office) and got the exact results as you have described.
The Plans and reports (htm) are generated by some utility "(sql) scrubsheet in OEM" which is not available in Oracle OEM version i am using at home->(Oracle9i Enterprise Edition Release 9.0.1.1.1 - Production)

That utility also tells you which step is executed when, in the Explain Plan.
It may not be new to you, but i was stunned using that.(please have a look at the reports attached)

anyways,
with your guidence and some work on it, i got some idea of the three major joins but these joins "occur" according to the

method and frequency of statistics taken and structure of the database. So where does developer come in picture for tuning queries involving such joins? i mean when i will explicitly change join or try to tune it further?

Also
please suggest me on following query

which is better practice of writing query, considering statistics are taken properly (with histograms) and data distribution as with our normal emp ,dept tables

select e.ename,d.dname from emp e, dept d where e.deptno = d.deptno and d.deptno = 30;
OR
select e.ename,d.dname from emp e, dept d where d.deptno = 30 and e.deptno = d.deptno and

If in a join both tables have index (one may have unique and another non-unique) are they considred equal ranked? Will

driving table concept matters here?


If a table has sequnce generated primary key then still do we need histogram for it?

Please suggest.

Thanks in Advance
Pratap


Re: Driving Table in Oracle 9i [message #171070 is a reply to message #170874] Mon, 08 May 2006 04:27 Go to previous messageGo to next message
Mahesh Rajendran
Messages: 10707
Registered: March 2002
Location: oracleDocoVille
Senior Member
Account Moderator
Well, the test case is tailored to produce the results. I strongly suggest to create a better robust test case see how things work ( for example, look into the previous case. I inserted records only into DEPT table. Still EMP table has only 3 distinct department numbers!!). And my definitions / descriptions on how SortMerge would work is not exactly correct(I just made an inaccurate assertion). More accurate examples/definitions are available in documentation.
And NO. I had never used OEM lately(9i and above). I find sql*plus just simple,sufficient for my work and i am very comfortable with it. So i am not aware of your neat little tool.
To answer you questions,
Both the sql should behave the same.
>>So where does developer come in picture for tuning queries involving such joins?
In my opinion , Developers/Programmers always have a better hand here (Or atleast in my case). You need to understand the 'data distribution' and application. Depending on that most of issues can be dealt in design stage itself. You need to understand 'join cardinality'.
Re: Driving Table in Oracle 9i [message #171073 is a reply to message #171070] Mon, 08 May 2006 04:38 Go to previous messageGo to next message
kumarsz
Messages: 180
Registered: March 2005
Location: canada
Senior Member
Hi Mahesh,
Thanks for your suggestions and advice,

However, can you give 2-3 examples where Developer is explicitly changing joins or forcing to change navigation (access path) of a query.

Now i have understood what joins are there and generally when they get used, but not sure when i will need to change its default behaviour.Please give examples and help me.

Thanks in Advance,
Pratap

Note : The feature in OEM, i am using is "SQL Scratchpad", Oracle version is - Oracle9i Enterprise Edition Release 9.2.0.7.0 - Production
you might have seen the report it generates ( i attached to this thread last time. Also each tells which step will occur at what sequence in Explain Plan)


Re: Driving Table in Oracle 9i [message #171111 is a reply to message #171073] Mon, 08 May 2006 08:03 Go to previous messageGo to next message
Mahesh Rajendran
Messages: 10707
Registered: March 2002
Location: oracleDocoVille
Senior Member
Account Moderator
I may not able to provide a test case today (I am on vacation).
But i will try some.
Please post your specific question / requirement.

Start by searching the forum (search for individual keywords)

http://www.orafaq.com/forum/m/156882/42800/?srch=set_column_stats#msg_156882
http://www.orafaq.com/forum/m/165796/42800/?srch=set_table_stats#msg_165796
http://www.orafaq.com/forum/m/149866/42800/?srch=set_table_stats#msg_149866

ALso look into hints. Applying hints may change the explain plan and you can understand what is happening.
Again, search the forum.

>>Also each tells which step will occur at what sequence in Explain Plan
All the tool is trying to interpret explain plan and provide a fancy output.
Analyze those reports closely. The same set of standard wording for each 'loop'. Only the table name changes.
You can write your own tool to do the same, provided you can interpret the explain plan as explained here.

http://download-east.oracle.com/docs/cd/B19306_01/server.102/b14211/ex_plan.htm#PFGRF009
Those (step)ID in explain plan output are nothing but the sequence of actual steps.

You may also want to be aware of something.
Explain plan is not a very accurate method but still a very useful method to begin with.
Consider this scenario. Users complain something is wrong with a report. Developer/DBA
identifies the sql and will execute that particular sql, look for plan/statistics whatever.
Are both situations same? Will the sql behave same? maybe or maynot be.
Because, now the sql is ISOLATED and did not reflect the same ENVIRONMENT as it was run before (system load,
Other waiting/blocking sessions, available are not considered now).
In these situations you may want to rely on SQLTracing (Get the PLAN of rogue SQL in its natural environment).

Once you can do that, You can also enable event 10053 and see why that particular plan was selected.
Using the event, you can see CBO did evaluate different plans and selected only one for some obvious reasons.
Re: Driving Table in Oracle 9i [message #171114 is a reply to message #171111] Mon, 08 May 2006 08:22 Go to previous messageGo to next message
Mahesh Rajendran
Messages: 10707
Registered: March 2002
Location: oracleDocoVille
Senior Member
Account Moderator
Almost all your questions are answered here

http://download-east.oracle.com/docs/cd/B19306_01/server.102/b14211/optimops.htm#sthref1388
Re: Driving Table in Oracle 9i [message #171115 is a reply to message #171114] Mon, 08 May 2006 08:25 Go to previous messageGo to next message
Frank
Messages: 7901
Registered: March 2000
Senior Member
Quote:

(I am on vacation)

Mahesh, go take a dive in the pool!
No more ORAFAQ for you this week(?)
Wink
icon11.gif  Re: Driving Table in Oracle 9i [message #171329 is a reply to message #171115] Tue, 09 May 2006 07:30 Go to previous messageGo to next message
Mahesh Rajendran
Messages: 10707
Registered: March 2002
Location: oracleDocoVille
Senior Member
Account Moderator
Laughing
Just an extended weekend spent entirely in my yard with some DIY projects. With a mixed case of Rochefort/Wesmalle/Gulden Draak all for myself, i call it a vacation. Cool

[Updated on: Fri, 08 October 2010 11:38]

Report message to a moderator

Re: Driving Table in Oracle 9i [message #171369 is a reply to message #171329] Tue, 09 May 2006 10:03 Go to previous messageGo to next message
kumarsz
Messages: 180
Registered: March 2005
Location: canada
Senior Member
Hi mahesh,
sorry, i was not knowing, change of work is rest for you.
people like you always motivate me and other so many.

i hope i am not stretching this thread much.
however i have gone through the links you referred in this thread which made my undestanding better.

But what i was looking for is example where we are "explicitly" changing joins or/and filtering condition, after seeing the Explain not as required or optimist.

May be i will send individual queries with plans and statistics when i stuck up and with your suggestions on that will improve myself on Tuning.

Thanks
Pratap
Re: Driving Table in Oracle 9i [message #171373 is a reply to message #171329] Tue, 09 May 2006 10:10 Go to previous messageGo to next message
Frank
Messages: 7901
Registered: March 2000
Senior Member
Quote:

Rochefort/Westvleteren/Gulden Draak

OT: I thought you lived in the US. Sounds more like Belgian/European delicacies to me [troll]or do some people in the US really have some sense of taste[/troll]

[Updated on: Tue, 09 May 2006 10:10]

Report message to a moderator

Re: Driving Table in Oracle 9i [message #171624 is a reply to message #171373] Wed, 10 May 2006 11:53 Go to previous message
Mahesh Rajendran
Messages: 10707
Registered: March 2002
Location: oracleDocoVille
Senior Member
Account Moderator
Edit:
Removed the posting.
OT

[Updated on: Wed, 10 May 2006 12:13]

Report message to a moderator

Previous Topic: Problem with order by clause
Next Topic: low librarycache hit ratio for indexes...
Goto Forum:
  


Current Time: Sat May 04 19:40:05 CDT 2024