it-swarm-eu.dev

Jaké jsou hlavní příčiny zablokování a lze jim zabránit?

Nedávno jedna z našich aplikací ASP.NET zobrazila chybu zablokování databáze a byla jsem požádána o kontrolu a opravu chyby. Podařilo se mi zjistit, že příčinou zablokování byla uložená procedura, která pečlivě aktualizovala tabulku v rámci kurzoru.

Toto je poprvé, co jsem viděl tuto chybu a nevěděl, jak ji účinně sledovat a opravit. Vyzkoušel jsem všechny možné způsoby, které znám, a nakonec jsem zjistil, že aktualizovaná tabulka nemá primární klíč! naštěstí to byl sloupec identity.

Později jsem našel vývojáře, který skriptoval databázi pro nasazení. Přidal jsem primární klíč a problém byl vyřešen.

Cítil jsem se šťastný a vrátil se ke svému projektu a provedl nějaký výzkum, abych zjistil příčinu toho patového bodu ...

Zřejmě to byl kruhový čekací stav, který způsobil zablokování. Aktualizace zjevně trvá déle bez primárního klíče než s primárním klíčem.

Vím, že to není dobře definovaný závěr, proto sem posílám příspěvek ...

  • Je problém chybějící primární klíč?
  • Existují nějaké jiné podmínky, které způsobují zablokování jiné než (vzájemné vyloučení, vydržení a čekání, žádné preempce a kruhové čekání)?
  • Jak mohu zabránit a sledovat zablokování?
57
CoderHawk

sledování zablokování je snazší z těchto dvou:

Ve výchozím nastavení jsou uváznutí uvázána v protokolu chyb. Můžete způsobit, že SQL zapíše zablokování do protokolu chyb s příznaky trasování 1204 a 3605.

Zápis informací o zablokování do protokolu chyb serveru SQL: DBCC TRACEON (-1, 1204, 3605)

Vypněte: DBCC TRACEOFF (-1, 1204, 3605)

Viz „Odstraňování problémů se zablokováním“, kde najdete diskuzi o příznaku trasování 1204 a výstupu, který získáte, když je zapnutý. https://msdn.Microsoft.com/en-us/library/ms178104.aspx

Prevence je obtížnější, v zásadě musíte dávat pozor na následující:

Kódový blok 1 blokuje zdroj A, pak zdroj B, v tomto pořadí.

Kódový blok 2 blokuje zdroj B, pak zdroj A, v tomto pořadí.

Toto je klasický stav, ve kterém může dojít k zablokování, pokud uzamčení obou zdrojů není atomové, blok kódu 1 může blokovat A a být předepjatý, pak blok kódu 2 blokuje B, než A získá zpět čas zpracování A. Nyní máte zablokování.

Chcete-li tomuto stavu zabránit, můžete udělat něco jako následující

Blok kódu A (psuedo kód)

Lock Shared Resource Z
    Lock Resource A
    Lock Resource B
Unlock Shared Resource Z
...

Blok kódu B (pseudo kód)

Lock Shared Resource Z
    Lock Resource B
    Lock Resource A
Unlock Shared Resource Z
...

nezapomenout odemknout A a B, když s nimi hotovo

tím by se zabránilo zablokování mezi kódovým blokem A a kódovým blokem B

Z pohledu databáze si nejsem jistý, jak postupovat v prevenci této situace, protože zámky jsou zpracovávány samotnou databází, tj. Zámky řádků/tabulek při aktualizaci dat. Tam, kde jsem viděl nejčastější problémy, je to, kde jste viděli své, uvnitř kurzoru. Kurzory jsou notoricky neefektivní, pokud je to možné, vyhýbejte se jim.

39
BlackICE

moje oblíbené články, které mohu číst a dozvědět se o deadlockech, jsou: Simple Talk - vystopování deadlocků a SQL Server Central - Použití Profileru k vyřešení deadlocků . Dají vám vzorky a rady, jak zvládnout sát situaci.

Stručně řečeno, pro vyřešení současného problému bych zkrátil transakce, vyřadil z nich nepotřebnou část, postaral se o pořadí použití objektů, viděl, jaká úroveň izolace je skutečně potřebná, nečetl nepotřebné data...

Ale lépe si přečtěte články, budou v radách příjemnější.

24
Marian

Někdy lze vyřešit zablokování přidáním indexování, protože umožňuje databázi zamknout jednotlivé záznamy spíše než celou tabulku, čímž omezíte soupeření a možnost uvíznutí věcí.

Například v InnoDB :

Pokud nemáte žádné indexy vhodné pro váš příkaz a MySQL musí prohledat celou tabulku, aby tento příkaz zpracoval, každý řádek tabulky se zamkne, což zase blokuje všechny vložení ostatními uživateli do tabulky. Je důležité vytvořit dobré indexy, aby vaše dotazy zbytečně nekontrolovaly mnoho řádků.

Dalším běžným řešením je vypnout transakční konzistenci, když to není potřeba, nebo jinak změnit vaši úroveň izolace , například, dlouhodobou úlohu pro výpočet statistik ... stačí obecná odpověď, nepotřebují přesná čísla, protože se mění pod vámi. A pokud to trvá 30 minut, nechcete, aby zastavil všechny ostatní transakce v těchto tabulkách.

...

Pokud jde o jejich sledování, záleží to na databázovém softwaru, který používáte.

16
Joe

Jen se vyvíjet na kurzorové věci. je to opravdu špatné. Uzamkne celou tabulku a poté jednotlivé řádky zpracuje.

Nejlepší je procházet řádky ve formě kurzoru pomocí smyčky while

Ve smyčce while se provede výběr pro každý řádek ve smyčce a zámek nastane vždy pouze na jednom řádku. Zbytek dat v tabulce je zdarma k dotazování, čímž se snižuje šance na zablokování.

Navíc je to rychlejší. Zajímá vás, proč jsou kurzory stejně.

Zde je příklad takové struktury:

DECLARE @LastID INT = (SELECT MAX(ID) FROM Tbl)
DECLARE @ID     INT = (SELECT MIN(ID) FROM Tbl)
WHILE @ID <= @LastID
    BEGIN
    IF EXISTS (SELECT * FROM Tbl WHERE ID = @ID)
        BEGIN
        -- Do something to this row of the table
        END

    SET @ID += 1  -- Don't forget this part!
    END

Pokud je vaše pole ID řídké, možná budete chtít vytáhnout samostatný seznam ID a iterovat to:

DECLARE @IDs TABLE
    (
    Seq INT NOT NULL IDENTITY PRIMARY KEY,
    ID  INT NOT NULL
    )
INSERT INTO @IDs (ID)
    SELECT ID
    FROM Tbl
    WHERE 1=1  -- Criteria here

DECLARE @Rec     INT = 1
DECLARE @NumRecs INT = (SELECT MAX(Seq) FROM @IDs)
DECLARE @ID      INT
WHILE @Rec <= @NumRecs
    BEGIN
    SET @ID = (SELECT ID FROM @IDs WHERE Seq = @Seq)

    -- Do something to this row of the table

    SET @Seq += 1  -- Don't forget this part!
    END
7

Chybí primární klíč ne problém. Alespoň sám. Nejprve nepotřebujete primární, abyste měli indexy. Za druhé, i když provádíte skenování tabulek (což se musí stát, pokud váš konkrétní dotaz nepoužívá index, zámek tabulky sám o sobě nezajistí zablokování. Proces zápisu by čekal na čtení a proces čtení by čekat na zápis, a samozřejmě čtení nebude muset čekat na sebe vůbec.

Přidání dalších odpovědí, na úrovni izolace transakce záleží, protože opakovatelné čtení a serializace jsou příčinou blokování „čtení“ až do konce transakce. Uzamčení zdroje nezpůsobí zablokování. Udržet to uzamčené. Operace zápisu vždy udržují svůj prostředek uzamčený až do konce transakce.

Moje oblíbená strategie prevence blokování využívá funkce „momentek“. Funkce čtení potvrzeného snímku znamená, že čtení nepoužívá zámky! A pokud potřebujete více kontroly než „Čtení potvrzeno“, je k dispozici funkce „Úroveň izolace výstřelu“. Ten umožňuje, aby došlo k serializované transakci (zde pomocí termínů MS), aniž by ostatní hráči blokovali.

Nakonec je možné zabránit jedné třídě uváznutí pomocí zámku aktualizace. Pokud přečtete a podržíte čtení (HOLD nebo pomocí opakovatelného čtení) a jiný proces provede totéž, pak se oba pokusí aktualizovat stejné záznamy, budete mít zablokování. Pokud však oba požadují zámek aktualizace, druhý proces bude čekat na první, zatímco umožní dalším procesům číst data pomocí sdílených zámků, dokud nebudou data skutečně zapsána. To samozřejmě nebude fungovat, pokud jeden z procesů stále vyžaduje sdílený zámek HOLD.

6
Gerard ONeill