dang
dang

Reputation: 2412

Improve join query in Oracle

I have a query which takes 17 seconds to execute. I have applied indexes on FIPS, STR_DT, END_DT but still it's taking time. Any suggestions on how I can improve the performance?

My query:

SELECT /*+ALL_ROWS*/ K_LF_SVA_VA.NEXTVAL VAL_REC_ID,       a.REC_ID,
   b.VID,
   1 VA_SEQ,
   51 VA_VALUE_DATATYPE,
   b.VALUE VAL_NUM,
   SYSDATE CREATED_DATE,
   SYSDATE UPDATED_DATE
   FROM CTY_REC  a JOIN FIPS_CONS b
 ON a.FIPS=b.FIPS AND a.STR_DT=b.STR_DT AND a.END_DT=b.END_DT;


 DESC CTY_REC;

 Name                Null Type          
------------------- ---- ------------- 
REC_ID                   NUMBER(38)    
DATA_SOURCE_DATE         DATE          
STR_DT                   DATE          
END_DT                   DATE          
VID_RECSET_ID            NUMBER        
VID_VALSET_ID            NUMBER        
FIPS                     VARCHAR2(255)


DESC FIPS_CONS;

Name          Null     Type          
------------- -------- ------------- 
STR_DT                 DATE          
END_DT                 DATE          
FIPS                   VARCHAR2(255) 
VARIABLE               VARCHAR2(515) 
VALUE                  NUMBER        
VID         NOT NULL   NUMBER        

Explain Plan:

Plan hash value: 919279614

--------------------------------------------------------------
| Id  | Operation           | Name                           |
--------------------------------------------------------------
|   0 | SELECT STATEMENT    |                                |
|   1 |  SEQUENCE           | K_VAL                          |
|   2 |   HASH JOIN         |                                |
|   3 |    TABLE ACCESS FULL| CTY_REC                        |
|   4 |    TABLE ACCESS FULL| FIPS_CONS                      |
--------------------------------------------------------------

I have added description of tables and explain plan for my query.

Upvotes: 3

Views: 75

Answers (4)

David דודו Markovitz
David דודו Markovitz

Reputation: 44941

If you wish to drive the optimizer to use the indexes,
replace /*+ all_rows */ with /*+ first_rows */

Upvotes: 0

David Aldridge
David Aldridge

Reputation: 52346

On the face of it, and without information on the configuration of the sequence you're using, the number of rows in each table, and the total number of rows projected from the query, it's possible that the execution plan you have is the most efficient one for returning all rows.

The optimiser clearly thinks that the indexes will not benefit performance, and this is often more likely when you optimise for all rows, not first rows. Index-based access is single block and one row at a time, so can be inherently slower than multiblock full scans on a per-block basis.

The hash join that Oracle is using is an extremely efficient way of joining data sets. Unless the hashed table is so large that it spills to disk, the total cost is only slightly more than full scans of the two tables. We need more detailed statistics on the execution to be able to tell if the hashed table is spilling to disk, and if it is the solution may just be modified memory management, not indexes.

What might also hold up your SQL execution is calling that sequence, if the sequence's cache value is very low and the number of records is high. More info required on that -- if you need to generate a sequential identifier for each row then you could use ROWNUM.

Upvotes: 3

Thorsten Kettner
Thorsten Kettner

Reputation: 94914

You should have at least these two indexes on the table:

  • CTY_REC(FIPS, STR_DT, END_DT)
  • FIPS_CONS(FIPS, STR_DT, END_DT)

which can still be sped up with covering indexes instead:

  • CTY_REC(FIPS, STR_DT, END_DT, REC_ID)
  • FIPS_CONS(FIPS, STR_DT, END_DT, VALUE, VID)

Upvotes: 0

Gordon Linoff
Gordon Linoff

Reputation: 1269763

This is basically your query:

SELECT . . .
FROM CTY_REC a JOIN
     FIPS_CONS b
     ON a.FIPS = b.FIPS AND a.STR_DT = b.STR_DT AND a.END_DT = b.END_DT;

You want a composite index on (FIPS, STR_DT, END_DT), perhaps on both tables:

create index idx_cty_rec_3 on cty_rec(FIPS, STR_DT, END_DT);
create index idx_fipx_con_3 on cty_rec(FIPS, STR_DT, END_DT);

Actually, only one is probably necessary but having both gives the optimizer more choices for improving the query.

Upvotes: 0

Related Questions