"Orden" är deterministisk ur ditt perspektiv endast om du inkluderar ORDER BY i din fråga. Om det är deterministiskt ur serverns perspektiv är en implementeringsdetalj som man inte kan lita på.
När det gäller låsning kan två identiska DML-satser blockera (men inte dödläge) varandra. Till exempel:
CREATE TABLE THE_TABLE (
ID INT PRIMARY KEY
);
Transaktion A:
INSERT INTO THE_TABLE VALUES(1);
Transaktion B:
INSERT INTO THE_TABLE VALUES(1);
Vid denna tidpunkt är transaktion B stoppad tills transaktion A antingen begår eller rullar tillbaka. Om A begår misslyckas B på grund av överträdelse av PRIMÄRNYCKEL. Om A rullar tillbaka, lyckas B.
Liknande exempel kan konstrueras för UPDATE och DELETE.
Den viktiga punkten är att blockering inte kommer att bero på exekveringsplan - oavsett hur Oracle väljer att optimera din fråga, kommer du alltid att ha samma blockeringsbeteende. Du kanske vill läsa om automatiska lås i DML Operations för mer information.
När det gäller döda -lås, de är möjliga att uppnå med flera påståenden. Till exempel:
A: INSERT INTO THE_TABLE VALUES(1);
B: INSERT INTO THE_TABLE VALUES(2);
A: INSERT INTO THE_TABLE VALUES(2);
B: INSERT INTO THE_TABLE VALUES(1); -- SQL Error: ORA-00060: deadlock detected while waiting for resource
Eller, möjligen med uttalanden som ändrar mer än en rad i olika ordning och en väldigt oturlig timing (kan någon bekräfta detta?).
--- UPPDATERING ---
Som svar på uppdateringen av din fråga, låt mig göra en allmän observation:Om samtidiga trådar av exekvering låser objekt i den konsekventa ordningen , dödlägen är omöjliga. Detta gäller för alla typer av låsning, vare sig det är mutexer i ditt genomsnittliga flertrådiga program (se t.ex. Herb Sutters tankar om låshierarkier) eller om det är databaser. När du ändrar ordningen på ett sådant sätt att två valfria lås "vänds", introduceras potentialen för dödläge.
Utan att skanna indexet uppdaterar du (och låser ) rader i en ordning och med index i en annan. Så detta är förmodligen vad som händer i ditt fall:
- Om du inaktiverar indexsökning för båda samtidiga transaktioner , båda låser rader i samma ordning [X], så inget dödläge är möjligt.
- Om du aktiverar indexsökning för bara en transaktion , låser de inte längre rader i samma ordning, därav risken för ett dödläge.
- Om du aktiverar indexsökning för båda transaktionerna , då låser båda raderna i samma ordning, och ett dödläge är omöjligt (försök med
alter session set optimizer_index_cost_adj = 1;
i båda sessionerna så får du se).
[X] Även om jag inte skulle förlita mig på att genomsökningar av hela bordet har en garanterad ordning – det kan bara vara hur nuvarande Oracle under dessa specifika omständigheter fungerar, och vissa framtida Oracle eller andra omständigheter kan ge ett annat beteende.
Så, förekomsten av index är tillfällig - den verkliga frågan är beställning. Det råkar vara så att beställning i UPDATE kan påverkas av ett index, men om vi kunde påverka beställningen på annat sätt skulle vi få liknande resultat.
Eftersom UPDATE inte har ORDER BY, kan du inte riktigt garantera ordningsföljden för låsning enbart med UPDATE. Men om du separerar låser från att uppdatera, då kan du garantera låsordningen:
SELECT ... ORDER BY ... FOR UPDATE;
Även om din ursprungliga kod orsakade låsningar i min Oracle 10-miljö, gör inte följande kod det:
Session 1:
declare
cursor cur is select * from deadlock_test where a > 0 order by a for update;
begin
while true loop
for locked_row in cur loop
update deadlock_test set a = -99999999999999999999 where current of cur;
end loop;
rollback;
end loop;
end;
/
Session 2:
alter session set optimizer_index_cost_adj = 1;
declare
cursor cur is select * from deadlock_test where a > 0 order by a for update;
begin
while true loop
for locked_row in cur loop
update deadlock_test set a = -99999999999999999999 where current of cur;
end loop;
rollback;
end loop;
end;
/