Link to home
Start Free TrialLog in
Avatar of trudyhlittle
trudyhlittleFlag for United States of America

asked on

Most efficient way to purge child table records

I have a business process that inserts parent records into a queue table.  Multiple detail records are written to two child tables.  Once the item is processed by the business, the parent record is deleted and inserted into a log table.  The detail records remain in their child tables.  We run a nightly job that purges the log table and all related detail records.  The log table is very large and this process takes about 45 minutes to complete.  Previously we were purging all records older than 30 days.  I was using the smallest key in the parent table to delete all records in the child tables with a key less than the parent key.  This seemed to work well since it used an indexed column to determine the delete criteria and avoided any table joins.  

We now have a new requirment to purge log records based on a client's retension criteria.  Most records we still purge after 30 days, however, some records we now keep 60 or 90 days.  My previous method of using the smallest key no longer works since there will be gaps in the data.  I can't use a cascade delete since the primary key is shared between the two queue and log tables.  I could use something similar to the following, but given the size of the log table it seems very inefficient.

DELETE FROM TRANSACTION_LOG_PROPERTIES
          WHERE TRANSACTION_ID IN
              ( SELECT TRANSACTION_ID FROM TRANSACTION_LOG
              WHERE TRANS_COMPLETE_DATE < cutOfDate);

What is the best way to clean up my detail records?  Thanks.  Also, we are running an Oracle 10g database.
Avatar of Piloute
Piloute
Flag of France image

Hi,

If I understand your problem, you'd like to delete records from TRANSACTION_LOG_PROPERTIES when "parent" lines are deleted from TRANSACTION_LOG. Right ?

And you can not use anymore the criteria TRANSACTION_ID, with DELETE where TRANSACTION_LOG_PROPERTIES.TRANSACTION_ID <  min( TRANSACTION_LOG.TRANSACTION_ID) because now you have gaps in the TRANSACTION_ID list ? Right ?

If this is also right, then I suggest the following :

1) delete first the lines in TRANSACTION_LOG.

2) then
          DELETE FROM TRANSACTION_LOG_PROPERTIES sub
          WHERE not exists (select 0 from TRANSACTION_LOG main
              WHERE main.TRANSACTION_ID = sub.TRANSACTION_ID);

'not exists' will use the index of your main table (TRANSACTION_ID) instead of browsing it completely like your 'in' statement would do.

Cheers,
P

Define the foreign key with the 'ON DELETE CASCADE' option as on this example from the fine Oracle® Database SQL Reference.
 
Avatar of trudyhlittle

ASKER

MikeOM_DBA, defining a ON DELETE CASCADE is not an option since records are inserted into the child tables at the time the queue recored is created, not when the log records are created.  I can't set up a foreign key relationship since records need to exist in the foreign key tables before they are created in the primary table I am purging

Piloute, thanks for you're suggestion.  I'll implement the change for tonight's purge on our test system and see how it performs.  Our test sytem doesn't contain nearly the volume of data our production environment does, but at least I should be able to get some metrics.
.  
I just thought of a problem with the suggested SQL.  In my previous processing I was getting the min(transaction_id) from both the queue and log tables and using whichever was the smallest to preform the delete on the child tables.  I can't use
DELETE FROM TRANSACTION_LOG_PROPERTIES sub
          WHERE not exists (select 0 from TRANSACTION_LOG main
              WHERE main.TRANSACTION_ID = sub.TRANSACTION_ID);
since there may be records still in the queue table that haven't been moved over to the log table yet for which I don't want to delete the child records.  I need to purge the child records where the record doesn't exist in either the transaction_queue or the transaction_log table.
ASKER CERTIFIED SOLUTION
Avatar of Piloute
Piloute
Flag of France image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
You can create deferred constraints which means the validation isn't performed until the transaction ends, usually at commit.
Thanks Piloute.  I used the 2nd recommendation, but reversed the data in the temporary table.  Instead of loading the table with keys to keep, I loaded them before the delete with keys I am going to delete then used a join on the temporary table to my child tables to delete all records that exist.

DELETE FROM TRANSACTION_LOG_PROPERTIES sub
          WHERE exists (select 0 from TEMP_TRANS_IDS_TO_DELETE main
              WHERE main.TRANSACTION_ID = sub.TRANSACTION_ID);