Reputation: 73
I have a job running in ORacle 10g production DB which syncs two DB tables A and B. The job fetches data from table A and inserts into table B. The job runs on a daily basis and for the past few months it started failing in production with the error "Error in retrieving data -54". On checking the store procedure, I could see that the job fails due to locking record issue when other jobs lock the records from table A and our job is not able to process the same. So I started searching for some possible solutions which I have given below.
Change the running time of the job so that it can process records. But this is not gonna help since table A is very critical and always used by production jobs. Also it has real time updates from the users.
Instead of "No WAIT" use "SKIP LOCKED" so that job will skip the locked records and run fine. But problem here is if locked records(This is always negligible compared to the huge production data) are skipped, there will be mismatch in the data in tables A and B for the day. Next day run will clear this problem since the job picks unpicked records of previous days also.But the slight mismatch for the job failed days may cause small problems
Let the job wait till all the records are unlocked and processed. but this again causes problem since we cannot predict how long job will be in waiting state(Long running state).
As of now one possible solution for me is to go with option 2 and ignore the slight deviation between table A and Bs data. Is there any other way in Oracle 10g Db to run the job without failing and long running and process all records. I wish to get some technical guidance on the same.
Thanks PB
Upvotes: 1
Views: 198
Reputation: 1927
I'd handle the exception (note, you'll have to either initialise your own EXCEPTION
or handle OTHERS
and inspect the SQLCODE
) and track the ids of the rows that were skipped. That way you can retry them once all the available records have been processed.
Something like this:
DECLARE
row_is_locked EXCEPTION;
PRAGMA EXCEPTION_INIT(row_is_locked, -54);
TYPE t_id_type IS VARRAY(1) OF INTEGER;
l_locked_ids t_id_type := t_id_type();
l_row test_table_a%ROWTYPE;
BEGIN
FOR i IN (
SELECT a.id
FROM test_table_a a
)
LOOP
BEGIN
-- Simulating your processing that requires locks
SELECT *
INTO l_row
FROM test_table_a a
WHERE a.id = i.id
FOR UPDATE NOWAIT;
INSERT INTO test_table_b
VALUES l_row;
-- This is on the basis that you're commiting
-- to release the lock on each row after you've
-- processed it; may not be necessary in your case
COMMIT;
EXCEPTION
WHEN row_is_locked THEN
l_locked_ids(l_locked_ids.LAST) := i.id;
l_locked_ids.EXTEND();
END;
END LOOP;
IF l_locked_ids.COUNT > 0 THEN
FOR i IN l_locked_ids.FIRST .. l_locked_ids.LAST LOOP
-- Reconcile the remaining ids here
NULL;
END LOOP;
END IF;
END;
Upvotes: 2