When doing concurrent MERGE
s while every session uses a different value (shown as *** in the snippet below) for the primary key column id
, everything is fine if I do it manually in 2 terminal sessions.
MERGE
INTO x
USING (SELECT *** as id FROM DUAL) MERGE_SRC
ON (x.id = MERGE_SRC.id)
WHEN MATCHED THEN UPDATE SET val = val + 1 WHERE id = ***
WHEN NOT MATCHED THEN INSERT VALUES (***, 99);
COMMIT;
However, running a multi-threaded load test with 3 or more threads, I will relatively quickly run into ORA-08177 with locked table
. Why is that? (And why is it non-deterministic in that it does not always happen when transactions overlap?)
The table was created using
create table x (id int primary key, val int);
SQL Server btw never throws exceptions with an equivalent MERGE statement, running the same experiment. That is even true when working on the same row simultaneously.
Is it because perhaps MERGE is not atomic, and the serializable mode runs optimistically, so that the race might only show with sufficient contention? Still, why does it happen even when not working on the same row concurrently?
Btw, my attempts to fix this using the strictest lock available were unsuccessful. So any ideas on how to make this atomic are very much appreciated. It looks like relaxing the isolation level would rid me of the exception, but risk inconsistencies in case there turn out to be 2 updates on the same row (otherwise why would it balk in serializable mode in the first place).
update
andif rowcount=0 then insert
? When in serializable mode, I guess I have to do a manual lock as well, right? – Evgeniy Berezovsky