Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.server -> Re: Indexes for selecting distinct values

Re: Indexes for selecting distinct values

From: JTommaney <cdos_jtommaney_at_comcast.net>
Date: 17 Oct 2005 14:01:39 -0700
Message-ID: <1129582899.683674.32490@g49g2000cwa.googlegroups.com>


Bitmaps indexes have some significant concurrency issues if the cust table is updated frequently. They can also be impacted if there are incremental loads against the tables. Don't implement unless you understand these issues.

Depending on your application requirements, MViews can significantly speed up the query, however I don't see a way to get the query to Incremental/Fast Refresh. You would likely get an ORA-12015: cannot create a fast refresh materialized view from a complex query error ( The union essentially implies that a sort operation goes on before identifying if that is a 'new' row ). You could create a Complete refresh materialized view, however.

An alternative approach to the original query may be to use the With subfactor querying syntax available in 9i to reduce the table access required. This would have the advantage of referencing the source rows once. This could be used in conjunction with a MView as well.

With cust_status_cd as
 ( select distinct status_1_cd, status_2_cd, status_3_cd from CUST

        where region_id = 9 )
select status_1_cd cd from cust_status_cd union
select status_2_cd from cust_status_cd
union
select status_3_cd from cust_status_cd;

As compared to using the original query with 3 indices on (region_id, status_<n>_cd) the results look pretty promising. Your mileage may vary, and this solution depends on the width of the table, and distribution of data values.

The test case below measures differences in resource usage with the Runstats package via asktom.oracle.com .

Differences look like (with run 2 using the With syntax) :

JT(11)@JTDB9I>exec runStats_pkg.rs_stop(); Run1 ran in 7980 hsecs
Run2 ran in 2680 hsecs
run 1 ran in 297.76% of the time

Name                                  Run1        Run2        Diff
. . .
LATCH.SQL memory manager worka       1,809         538      -1,271
STAT...redo size                     1,816       3,372       1,556
STAT...prefetched blocks             4,110       1,370      -2,740
STAT...session logical reads         4,452       1,541      -2,911
STAT...consistent gets               4,442       1,517      -2,925
STAT...buffer is not pinned co       4,416       1,477      -2,939
STAT...no work - consistent re       4,416       1,477      -2,939
STAT...table scan blocks gotte       4,416       1,477      -2,939
STAT...free buffer requested         4,416       1,475      -2,941
STAT...physical reads                4,416       1,474      -2,942
LATCH.cache buffers lru chain        4,486       1,500      -2,986
STAT...Elapsed Time                  7,982       2,684      -5,298
LATCH.cache buffers chains          16,106       6,095     -10,011
STAT...session pga memory max            0      69,656      69,656
STAT...sorts (rows)                153,999      53,380    -100,619
STAT...table scan rows gotten    1,665,405     555,452  -1,109,953

Run1 latches total versus runs -- difference and pct
Run1        Run2        Diff       Pct
30,066      12,676     -17,390    237.19%

PL/SQL procedure successfully completed.


insert into cust

select rownum, mod(rownum,11),
	decode(mod(rownum,3),0,'A',1,'B',2,'C'),
	decode(mod(rownum,5),0,'e',1,'f',2,'g',3,'h',4,'i'),
	decode(mod(rownum,7),0,'u',1,'v',2,'w',3,'x',4,'y',5,'z',6,'a')
from  all_objects,
	(select 'x' from all_objects where rownum <= 15) multiplier
 where rownum <= 1000000; -- actually about 555,000 rows created. commit;
create index cust_reg_cd1 on cust(region_id,  status_1_cd);
create index cust_reg_cd2 on cust(region_id,  status_2_cd);
create index cust_reg_cd3 on cust(region_id,  status_3_cd);

exec dbms_stats.gather_table_stats('JTOMMANEY','cust', cascade => true);

exec runStats_pkg.rs_start;

select distinct status_1_cd from cust where region_id = 9 union
select distinct status_2_cd from cust where region_id = 9 union
select distinct status_3_cd from cust where region_id = 9;

exec runStats_pkg.rs_middle;

with cust_status_cd as
 ( select distinct status_1_cd, status_2_cd, status_3_cd from cust

        where region_id = 9 )
select status_1_cd cd from cust_status_cd union
select status_2_cd from cust_status_cd
union
select status_3_cd from cust_status_cd;

exec runStats_pkg.rs_stop();


Received on Mon Oct 17 2005 - 16:01:39 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US