"Pořadí" je deterministické z vašeho pohledu pouze pokud do dotazu zahrnete ORDER BY. Zda je deterministický z pohledu serveru je implementační detail, na který se nelze spoléhat.
Pokud jde o zamykání, dva identické příkazy DML se mohou vzájemně blokovat (ale nikoli uváznout). Například:
CREATE TABLE THE_TABLE (
ID INT PRIMARY KEY
);
Transakce A:
INSERT INTO THE_TABLE VALUES(1);
Transakce B:
INSERT INTO THE_TABLE VALUES(1);
V tomto okamžiku je transakce B zastavena dokud se transakce A buď nepotvrdí, nebo se vrátí zpět. Pokud se A zaváže, B selže z důvodu porušení PRIMÁRNÍHO KLÍČE. Pokud se A vrátí zpět, B uspěje.
Podobné příklady lze vytvořit pro UPDATE a DELETE.
Důležitým bodem je, že blokování nebude záviset na plánu provádění – bez ohledu na to, jak se Oracle rozhodne optimalizovat váš dotaz, budete mít vždy stejné chování při blokování. Možná si budete chtít přečíst o automatických uzamykáních v operacích DML pro více informací.
Pokud jde o mrtvé -zámky, lze jich dosáhnout pomocí více příkazů. Například:
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
Nebo možná s prohlášeními, která upravují více než jeden řádek v různém pořadí a s velmi nešťastným načasováním (může to někdo potvrdit?).
--- AKTUALIZACE ---
V reakci na aktualizaci vaší otázky mi dovolte provést obecnou poznámku:Pokud souběžná vlákna provádění uzamknou objekty v konzistentním pořadí , uváznutí není možné. To platí pro jakýkoli druh zamykání, ať už jde o mutexy ve vašem průměrném vícevláknovém programu (např. viz úvahy Herba Suttera o hierarchiích zámků), nebo ať už jde o databáze. Jakmile změníte pořadí tak, že se "překlopí" libovolné dva zámky, objeví se potenciál pro zablokování.
Bez skenování index aktualizujete (a zamykáte ) řádky v jednom pořadí a s indexem v jiném. Takže ve vašem případě se pravděpodobně stane toto:
- Pokud zakážete prohledávání indexů pro obě souběžné transakce , oba zamykají řádky ve stejném pořadí [X], takže není možné žádné uváznutí.
- Pokud povolíte skenování indexu pouze pro jednu transakci , již nezamykají řádky ve stejném pořadí, a proto existuje možnost uváznutí.
- Pokud povolíte prohledávání indexů pro obě transakce , pak opět oba zamykají řádky ve stejném pořadí a uváznutí není možné (pokračujte a zkuste
alter session set optimizer_index_cost_adj = 1;
v obou relacích a uvidíte).
[X] I když bych nespoléhal na to, že skenování celé tabulky bude mít zaručenou objednávku – může to být jen tím, jak současný Oracle za těchto specifických okolností funguje, a některé budoucí Oracle nebo jiné okolnosti mohou způsobit odlišné chování.
Přítomnost indexu je tedy náhodná – skutečným problémem je řazení. Stává se, že řazení v UPDATE může být ovlivněno indexem, ale pokud bychom mohli ovlivnit řazení jiným způsobem, dostali bychom podobné výsledky.
Vzhledem k tomu, že UPDATE nemá ORDER BY, nemůžete skutečně zaručit pořadí uzamčení pouze UPDATE. Pokud se však oddělíte uzamknutí před aktualizací, pak můžete zaručit pořadí zámku:
SELECT ... ORDER BY ... FOR UPDATE;
Zatímco váš původní kód způsobil uváznutí v mém prostředí Oracle 10, následující kód ne:
Relace 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;
/
Relace 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;
/