简体   繁体   中英

Advise to improve Query Performance (Oracle)

I have a table (A) with 116,317,979 records and it is growing everyday by around 750,000 records per day.

As per my requirement I want to efficiently fetch last 3 complete days data from the table using a date column (date-time is stored in the column). So the query will be

select * from A where date_column >= trunc(sysdate) - 3

I also need to join the table A with table B such that

select * from A 
left outer join B 
on A.X = B.X and A.Y = B.Y and A.Z = B.Z and B.M = 'XYZ' and B.N = 'UIM'
where A.date_column >= trunc(sysdate) - 3

Unique Index & PK of Table B (X,Y,Z,M,N)

Unique Index & PK of Table A (ID)


Proposed IDX 1 on Table A (date_column)

Proposed IDX 2 on Table A (X,Y,Z)

Time without Indexes 34 sec
Time with IDX 1      32 sec
Time with IDX 1 & 2  27 sec //Sorry about the mistype

By only adding an index on A.date_column I thought I could significantly increase the performance but my tests results are negative. Are there any other hints with which i can increase the performance apart from adding new indexes? Is there any harm in adding indexes like these in the long run.

OR

It is better to create another table and populate last 3 days data in it somehow live(using db trigger). I can easily have another process to purge data older than 3 days every night.

Thanks in advance.

Oracle partitioning would make sense here, but this is an extra cost option even for Enterprise Edition. In case partitioning is not available - the separate table keeping last 3 days should be the best for performance. You should try it.

If you want to get maximum from indexes then you can consider to play a bit with the physical parameters:

  • if date column is not updated and the data is rarely deleted then you can set PCTFREE 0
  • looking at your final query, I would suggest to create an index on trunc(date) column and use compression -> in this case each index data block store much more entries. In this case the final query condition should be trunc(date_column) >= trunc(sysdate) - 3

Depending on the selectivity of X,Y,Z in table A, it could make sense to compress them as well. So I suggest to check two cases:

  1. create index trunc_date_ai on A(trunc(date_column)) pctfree 0 compress; + your IDX2
  2. create index trunc_date_ai on A(trunc(date_column),X,Y,Z) pctfree 0 compress; pctfree 0 should be used in case X,Y,Z are not updated in table A. compress keyword here makes compression for all 4 columns, so it is worth using if X,Y,Z values are highly repeatable in table A for particular trunc(date_column).

To force the index usage you can hint the query, for example like this:

select --+ index (A trunc_date_ai)
       * 
from   A left outer join B 
on A.X = B.X and A.Y = B.Y and A.Z = B.Z and B.M = 'XYZ' and B.N = 'UIM'
where trunc(A.date_column) >= trunc(sysdate) - 3

You should check the execution plan to see if the indexes are being used. I am guessing that the index on date_column is not used and the difference between 32 and 34 seconds is just noise.

I would suggest an index on A(date_column, X, Y, Z) for this query.

Is there harm to adding indexes? Well, they add overhead on insert s/ update s/ delete s. If your inserts are transactional, then you are inserting about 10 rows per second -- not counting updates and deletes. If your peaks are significantly higher than that and your hardware is not very good, then the indexes could slow things down. If the additional rows are added in batches, I wouldn't worry about the overhead.

I doubt that splitting the table out into a separate 3-day table would make much of a difference. But why listen to me? Try it out. Take the last 3+ days of data, dump it into a table, index it properly and see if the queries are faster.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM