Sql si tabulky uzamyká sám, ale jde o to že někdy když se posílá větší množství dat a dojde ke kolizi zůstane tabulka uzamčená několik minut, používám transakce, a v transakcích rollback. Nejspíš to způsobuje on, že při neúspěchu operace trvá dlouhodou dobu než to vrátí do původního stavu.
Jakým způsobem byla tabulka "uzamčena"?
Posílám data vzdáleně, tzn. spustím nějak uloženou proceduru která zpracovává pomocí transakcí určité úlohy nad tabulkami. Pokud dojde k přístupu jiného connections na uzamčenou tabulku, mám nastavený LOCK_TIMEOUT 1000, tak někdy dojde ke kolizi, tam právě dojde k rollbacku. Sql mi pak zahlásí : Lock request time out period exceeded. Chci aby pokud dojde ke kolizi, aby ty data které ještě nezpracoval aby je zahodil a ty které už provedl aby nechal tak. Nevím jestli když v transakci dám pokud nenastane chyba aby byl commit tran a pokud dojde k chybě aby se nestalo nic.
Pokud by mel zahodit nezpracovana data, bylo by treba zpracovavat je v cyklu po castech (po zaznamu) a kazde zpracovani uzavrit do transakce. Pak by nedochazelo k zamykani, ke kteremu dochazi ted a bylo by zajisteno, ze v pripade, ze se provede jdna cast, budou data konzistentni.
Vždy se provádí úprava maximálně nad třeba tabulkama v jedné transakci, těch transakcí mám několik. Něco jako toto : DECLARE ZMENY CURSOR KEYSET FOR SELECT UDALOST, OBJE_ID_POMOCNE, OBJE_ID FROM tabulka
OPEN ZMENY FETCH NEXT FROM ZMENY INTO @UDALOST, @OBJE_ID_POMOCNE, @OBJE_ID ´ WHILE (@@fetch_status <> -1) BEGIN
BEGIN TRAN
INSERT INTO [tabulka1] ([UZIVATEL], [OBJE_ID_POMOCNE], [OBJE_ID]) SELECT @UDALOST, @OBJE_ID_POMOCNE, @OBJE_ID
INSERT INTO [tabulka2] ([UZIVATEL], [OBJE_ID_POMOCNE], [OBJE_ID]) SELECT @UDALOST, @OBJE_ID_POMOCNE, @OBJE_ID
IF (@@ERROR <> 0) BEGIN ROLLBACK TRAN END ELSE BEGIN COMMIT TRAN END
BEGIN TRAN
INSERT INTO #xp_results_polo EXEC [Everend2006].[dbo].[SQL_SQL] @OBJE_ID SET @ID_OBJE_OBJE = (SELECT TOP 1 ID FROM #xp_results_polo)
IF (@@ERROR <> 0) BEGIN ROLLBACK TRAN END ELSE BEGIN IF @ID_OBJE_OBJE > 0 BEGIN COMMIT TRAN END ELSE BEGIN ROLLBACK TRAN END END
FETCH NEXT FROM ZMENY INTO @UDALOST,@OBJE_ID_POMOCNE END CLOSE ZMENY DEALLOCATE ZMENY
Tobe nevadi, ze když to spadne, tak to v tabulkach tabulka1 a tabulka2 zapsáno bude a v #xp_results_polo ne?
No mám to rozdělené na cykly, pokud jeden uzel projde, druhý neprojde, při příštím spojení to projde co se provedlo a co ne. Takže pokud první transakce při zápisu do tabulky 1,2 projde a spadne to u druhé transakce, nevadí to. Dřív jsem to měl jako že ve velké transakci, takže tyto dvě byli vnořené. Ale to my přišlo že to není asi moc dobré.
V prvnim cyklu jsou 2 tranakce za sebou, pokud mi neunikly nejake BEGIN-END Pokud se prvni provede a druha ne, nevadi to?
Chtěl jsem to udělat pokud možno tak aby se provádělo co nejmíň operací v jedné transakci, aby při případné chybě trval rollback co nejkratší dobu. Je pravda že cursor je dost pomalý ale zatím jsem nepřišel na jeho náhradu. Dejme tomu že cursor prochází tabulku ve které je zhruba tak 100 záznamů. Stejně mi nejde narozum, proč se to uzamkne na tak dlouhou dobu jakou je třeba 5 minut. Možná tam mám něco špatně zapsané. V jednu chvíli pracuje nad stejnýma tabulkama tak maximálně deset uživatelů.
No je to něco jako asi takto, to co jsem vypsal je jen část : Pokud 1.transakce proběhne úspěšně, provádí se 2.transakce, pokud druhá uspěje provádí se 3.transakce. Pokud 1.transakce proběhne úspěšně, provádí se 2.transakce, pokud druhá neuspěje, dojde k rollbacku 2.transakce, první zůstavá vyřízená, 3.transakce se už neprovede.
Osobně bych to řešil takto: V cyklu (nebo bez něj) bych si vše zpracoval do pomocnych tabulek bez transakce. Jakmile bych měl připravena data pri insert, zahájím transakci, nasypu najednou pomoi INSERT INTO - SELECT ... data z pomocnych tabulek do ostrych a transakci ukončím. Pokud jde o stovky záznamů, musí to být hotové během chviličky.
To by se dalo jenomže já potřebuju ještě než data vložím do tabulky rozhodnout o tom jestli ty data do tabulky můžu uložit, jedná se o skladové zásoby, tzn. kontroluju jestli množství nepřesahuje dovolenou mez, pak taky kontroluju nedělitelné množství. Takže to je problém. A že bych počítal kolik množství daného zboží obsahuje dávka a pak to kontroloval oproti dané mezi, to asi taky není dobré. A navíc dávka neobsahuje jenom příkaz insert, ale taky update a delete.
Tak nakonec jsem to částečně zafixoval. Jednak jsem zvýšil lock_timeout a všiml jsem si že nemám naindexovanou jednu tabulku ze které čtu a ve které je nějakých 40000 řádků. Takže po těchto dvou úpravách když už dojde k hlášce lock request out of period, zámek se během sekundy uvolní.
Sql si tabulky uzamyká sám, ale jde o to že někdy když se posílá větší množství dat a dojde ke kolizi zůstane tabulka uzamčená několik minut, používám transakce, a v transakcích rollback. Nejspíš to způsobuje on, že při neúspěchu operace trvá dlouhodou dobu než to vrátí do původního stavu.
Jakým způsobem byla tabulka "uzamčena"?
Posílám data vzdáleně, tzn. spustím nějak uloženou proceduru která zpracovává pomocí transakcí určité úlohy nad tabulkami. Pokud dojde k přístupu jiného connections na uzamčenou tabulku, mám nastavený LOCK_TIMEOUT 1000, tak někdy dojde ke kolizi, tam právě dojde k rollbacku. Sql mi pak zahlásí : Lock request time out period exceeded. Chci aby pokud dojde ke kolizi, aby ty data které ještě nezpracoval aby je zahodil a ty které už provedl aby nechal tak. Nevím jestli když v transakci dám pokud nenastane chyba aby byl commit tran a pokud dojde k chybě aby se nestalo nic.
Pokud by mel zahodit nezpracovana data, bylo by treba zpracovavat je v cyklu po castech (po zaznamu) a kazde zpracovani uzavrit do transakce.
Pak by nedochazelo k zamykani, ke kteremu dochazi ted a bylo by zajisteno, ze v pripade, ze se provede jdna cast, budou data konzistentni.
Vždy se provádí úprava maximálně nad třeba tabulkama v jedné transakci, těch transakcí mám několik.
Něco jako toto :
DECLARE ZMENY CURSOR
KEYSET
FOR SELECT UDALOST, OBJE_ID_POMOCNE, OBJE_ID
FROM tabulka
OPEN ZMENY
FETCH NEXT FROM ZMENY INTO @UDALOST, @OBJE_ID_POMOCNE, @OBJE_ID ´
WHILE (@@fetch_status <> -1)
BEGIN
BEGIN TRAN
INSERT INTO [tabulka1]
([UZIVATEL], [OBJE_ID_POMOCNE], [OBJE_ID])
SELECT @UDALOST, @OBJE_ID_POMOCNE, @OBJE_ID
INSERT INTO [tabulka2]
([UZIVATEL], [OBJE_ID_POMOCNE], [OBJE_ID])
SELECT @UDALOST, @OBJE_ID_POMOCNE, @OBJE_ID
IF (@@ERROR <> 0)
BEGIN
ROLLBACK TRAN
END
ELSE
BEGIN
COMMIT TRAN
END
BEGIN TRAN
INSERT INTO #xp_results_polo
EXEC [Everend2006].[dbo].[SQL_SQL] @OBJE_ID
SET @ID_OBJE_OBJE = (SELECT TOP 1 ID FROM #xp_results_polo)
IF (@@ERROR <> 0)
BEGIN
ROLLBACK TRAN
END
ELSE
BEGIN
IF @ID_OBJE_OBJE > 0
BEGIN
COMMIT TRAN
END
ELSE
BEGIN
ROLLBACK TRAN
END
END
FETCH NEXT FROM ZMENY INTO @UDALOST,@OBJE_ID_POMOCNE
END
CLOSE ZMENY
DEALLOCATE ZMENY
Tobe nevadi, ze když to spadne, tak to v tabulkach tabulka1 a tabulka2 zapsáno bude a v #xp_results_polo ne?
No mám to rozdělené na cykly, pokud jeden uzel projde, druhý neprojde, při příštím spojení to projde co se provedlo a co ne. Takže pokud první transakce při zápisu do tabulky 1,2 projde a spadne to u druhé transakce, nevadí to. Dřív jsem to měl jako že ve velké transakci, takže tyto dvě byli vnořené. Ale to my přišlo že to není asi moc dobré.
V prvnim cyklu jsou 2 tranakce za sebou, pokud mi neunikly nejake BEGIN-END
Pokud se prvni provede a druha ne, nevadi to?
Chtěl jsem to udělat pokud možno tak aby se provádělo co nejmíň operací v jedné transakci, aby při případné chybě trval rollback co nejkratší dobu.
Je pravda že cursor je dost pomalý ale zatím jsem nepřišel na jeho náhradu.
Dejme tomu že cursor prochází tabulku ve které je zhruba tak 100 záznamů.
Stejně mi nejde narozum, proč se to uzamkne na tak dlouhou dobu jakou je třeba 5 minut.
Možná tam mám něco špatně zapsané.
V jednu chvíli pracuje nad stejnýma tabulkama tak maximálně deset uživatelů.
No je to něco jako asi takto, to co jsem vypsal je jen část :
Pokud 1.transakce proběhne úspěšně, provádí se 2.transakce, pokud druhá uspěje provádí se 3.transakce.
Pokud 1.transakce proběhne úspěšně, provádí se 2.transakce, pokud druhá neuspěje, dojde k rollbacku 2.transakce, první zůstavá vyřízená, 3.transakce se už neprovede.
Osobně bych to řešil takto:
V cyklu (nebo bez něj) bych si vše zpracoval do pomocnych tabulek bez transakce.
Jakmile bych měl připravena data pri insert, zahájím transakci, nasypu najednou pomoi INSERT INTO - SELECT ... data z pomocnych tabulek do ostrych a transakci ukončím. Pokud jde o stovky záznamů, musí to být hotové během chviličky.
To by se dalo jenomže já potřebuju ještě než data vložím do tabulky rozhodnout o tom jestli ty data do tabulky můžu uložit, jedná se o skladové zásoby, tzn. kontroluju jestli množství nepřesahuje dovolenou mez, pak taky kontroluju nedělitelné množství. Takže to je problém. A že bych počítal kolik množství daného zboží obsahuje dávka a pak to kontroloval oproti dané mezi, to asi taky není dobré. A navíc dávka neobsahuje jenom příkaz insert, ale taky update a delete.
Tak nakonec jsem to částečně zafixoval. Jednak jsem zvýšil lock_timeout a všiml jsem si že nemám naindexovanou jednu tabulku ze které čtu a ve které je nějakých 40000 řádků. Takže po těchto dvou úpravách když už dojde k hlášce lock request out of period, zámek se během sekundy uvolní.