> I don't think Oracle will have a real problem with 15 tables or 1,000
rows.
> If the ref tables are quite small then they won't even be worth indexing
-
> Oracle will just read the entire table at one anyway.
Not necessarily. There can be quite a difference between using
an index on a small table, and not using one.
The following will illustrate:
#-----------------------------------------------------------
drop table fts1;
drop table fts2;
create table fts1 (
refcode varchar2 (6) not null
, description varchar2(30) not null
);
begin
for i in 1..100
loop
execute immediate
'insert into fts1 values('
|| '''' || 'C' || i || '''' || ','
|| '''' || 'Code ' || i || ''''
|| ')';
end loop;
commit;
end;
/
create table fts2
as
select *
from fts1;
create index fts2_code_idx
on fts2(refcode);
analyze table fts1 compute statistics;
analyze table fts2 compute statistics;
#-----------------------------------------------------------
Now the test harness is run. This is based on Tom Kytes
run_stats test harness. http://asktom.oracle.com/~tkyte/runstats.html
#-----------------------------------------------------------
-- test_harness.sql
-- from Tom Kyte - asktom.oracle.com/~tkyte/runstats.html
-- see ~/oracle/dba/run_stats for all files
declare
l_start number;
--add any other variables you need here for the test...
begin
delete from run_stats;
commit;
-- start by getting a snapshot of the v$ tables
insert into run_stats select 'before', stats.* from stats;
-- and start timing...
l_start := dbms_utility.get_time;
-- for things that take a very small amount of time, I like to
-- loop over it time and time again, to measure something "big"
-- if what you are testing takes a long time, loop less or maybe
-- not at all
for i in 1 .. 1000
loop
-- your code here for approach #1
declare
r_code fts1%rowtype;
begin
select refcode, description into r_code
from fts1
where refcode = 'C25';
select refcode, description into r_code
from fts1
where refcode = 'C50';
select refcode, description into r_code
from fts1
where refcode = 'C75';
select refcode, description into r_code
from fts1
where refcode = 'C99';
end;
end loop;
dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs'
);
-- get another snapshot and start timing again...
insert into run_stats select 'after 1', stats.* from stats;
l_start := dbms_utility.get_time;
for i in 1 .. 1000
loop
-- your code here for approach #2
declare
r_code fts2%rowtype;
begin
select /*+ index(fts2, fts2_code_idx) */
refcode, description into r_code
from fts2
where refcode = 'C25';
select /*+ index(fts2, fts2_code_idx) */
refcode, description into r_code
from fts2
where refcode = 'C50';
select /*+ index(fts2, fts2_code_idx) */
refcode, description into r_code
from fts2
where refcode = 'C75';
select /*+ index(fts2, fts2_code_idx) */
refcode, description into r_code
from fts2
where refcode = 'C99';
end;
end loop;
dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs'
);
insert into run_stats select 'after 2', stats.* from stats;
end;
/
#-----------------------------------------------------------
The results:
17:56:17 rsysdevdb.radisys.com - jkstill@dv01 SQL> @th
57 hsecs
44 hsecs
PL/SQL procedure successfully completed.
The code using the index was only marginally faster. The
real savings are in resources not consumed when an index is used.
17:56:14 rsysdevdb.radisys.com - jkstill@dv01 SQL> @run_stats
NAME RUN1 RUN2 DIFF
---------------------------------------- ---------- ---------- ----------
STAT...calls to get snapshot scn: kcmgss 4002 4001 -1
STAT...deferred (CURRENT) block cleanout 3 2 -1
applications
STAT...enqueue requests 1 0 -1
STAT...free buffer requested 0 1 1
LATCH.active checkpoint queue latch 2 0 -2
STAT...messages sent 0 2 2
LATCH.undo global data 2 5 3
LATCH.enqueue hash chains 0 4 4
LATCH.redo allocation 9 13 4
LATCH.session allocation 0 8 8
LATCH.enqueues 0 12 12
LATCH.session idle bit 0 14 14
STAT...recursive cpu usage 54 40 -14
LATCH.cache buffers lru chain 20 1 -19
LATCH.shared pool 4 28 24
LATCH.checkpoint queue latch 44 1 -43
STAT...redo size 20944 21016 72
LATCH.library cache 8084 8194 110
STAT...session uga memory 3184 0 -3184
STAT...buffer is not pinned count 4000 8000 4000
STAT...table scan blocks gotten 4000 0 -4000
STAT...table scans (short tables) 4000 0 -4000
STAT...table fetch by rowid 0 4000 4000
STAT...consistent gets 4005 8006 4001
STAT...session logical reads 20017 8020 -11997
STAT...db block gets 16012 14 -15998
LATCH.cache buffers chains 40098 16081 -24017
STAT...table scan rows gotten 400000 0 -400000
28 rows selected.
The RUN2 column contains the stats for the SQL using an index. There are
substantial resource savings here.
This was on a table with 100 rows, it all fits in one 8k block, yet the
use of an index made the code much more efficient.
My thanks to Cary Millsap, and everyone else on this list that
has pointed this out.
Jared
--
Please see the official ORACLE-L FAQ: http://www.orafaq.net
--
Author:
INET: [EMAIL PROTECTED]
Fat City Network Services -- 858-538-5051 http://www.fatcity.com
San Diego, California -- Mailing list and web hosting services
---------------------------------------------------------------------
To REMOVE yourself from this mailing list, send an E-Mail message
to: [EMAIL PROTECTED] (note EXACT spelling of 'ListGuru') and in
the message BODY, include a line containing: UNSUB ORACLE-L
(or the name of mailing list you want to be removed from). You may
also send the HELP command for other information (like subscribing).