sql >> Databáze >  >> RDS >> Oracle

Může dojít k uváznutí se stejnou metodou přístupu?

"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;
/


  1. Proč Postgres nepoužívá index?

  2. PostgreSQL -musí se objevit v klauzuli GROUP BY nebo být použit v agregační funkci

  3. Proč dostávám parametr 2 nemohu předat chybou odkazu, když používám bindParam s konstantní hodnotou?

  4. Jak spouštět aplikace PHP 5 s MySQL 8.0 na CentOS 7