Forum » Programiranje » [MariaDB] Dosegljivost podatkov med DELETE + INSERT operacijo.
[MariaDB] Dosegljivost podatkov med DELETE + INSERT operacijo.
Temo vidijo: vsi
HotBurek ::
Pozdravljeni.
Evo, nov dan, nov izziv.
V tabeli (MariaDB, InnoDB) izvajam "update" na način, da skupaj zvežem prvo DELETE, potem pa INSERT.
Na začetku uporabim START TRANSACTION, potem sledita DELETE in INSERT, ter COMMIT na koncu.
Zanima me, kako (in če) bi se dalo narediti, da so podatki v taki tabeli vedno na volja?
Se pravi med izvajanjem COMMIT-a, kaj se takrat dogaja v bazi?
Ali lahko pride do "vmesne" situacije, ko SELECT ne bi nič vrnil, ker se je DELETE že izvedel, INSERT pa še ne, in je takrat prazna tabela?
Evo, nov dan, nov izziv.
V tabeli (MariaDB, InnoDB) izvajam "update" na način, da skupaj zvežem prvo DELETE, potem pa INSERT.
Na začetku uporabim START TRANSACTION, potem sledita DELETE in INSERT, ter COMMIT na koncu.
Zanima me, kako (in če) bi se dalo narediti, da so podatki v taki tabeli vedno na volja?
Se pravi med izvajanjem COMMIT-a, kaj se takrat dogaja v bazi?
Ali lahko pride do "vmesne" situacije, ko SELECT ne bi nič vrnil, ker se je DELETE že izvedel, INSERT pa še ne, in je takrat prazna tabela?
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
pegasus ::
Začni tu: ACID @ Wikipedia
In potem beri specifično za tvojo verzijo baze, kako ima to implementirano. InnoDB je pogojno sprejemljiv.
In potem beri specifično za tvojo verzijo baze, kako ima to implementirano. InnoDB je pogojno sprejemljiv.
c3p0 ::
Za "vmesne" situacije sploh imamo transakcije, a ne. Drugače pa obstajajo locki na več nivojih in drugi queryji pridno čakajo, da se lock sprosti.
Lahko pa še tako dobro bazo enostavno uničiš performance s slabimi queryji.
Lahko pa še tako dobro bazo enostavno uničiš performance s slabimi queryji.
klemenSLO ::
TEhnično gledano maš NOLOCK oz READ unCOMMITED opcijo.
BOlj je vprašanje vsebinske narave --> ali si lahko privoščiš da uporabnik morebiti dobi napačne podatke?
@c3p0: Lahko pa še tako dobro bazo enostavno uničiš performance s slabimi queryji. Ha, točno to. Še tok dober HW ne reši slabih queryjev...
BOlj je vprašanje vsebinske narave --> ali si lahko privoščiš da uporabnik morebiti dobi napačne podatke?
@c3p0: Lahko pa še tako dobro bazo enostavno uničiš performance s slabimi queryji. Ha, točno to. Še tok dober HW ne reši slabih queryjev...
Life is not measured in minutes, but in MOMENTS...
kuall ::
Začni tu: ACID @ Wikipedia
In potem beri specifično za tvojo verzijo baze, kako ima to implementirano. InnoDB je pogojno sprejemljiv.
kaj bo bral ene debilne romane, ko pa je veliko bolj zanesljivo in lažje naredit en svoj test
ms sql dela tako, da če v transkaciji brišeš iz tabele potem je tabela zaklenena ves čas transakcije, ne samo v času brisanja. kak drug sql server pa je lahko drugače implementiran
trest
--create table t (id int identity , acname varchar (100))
--create table t2 (id int identity , acname varchar (100))
insert into t (acname ) values ('1')
insert into t2 (acname ) values ('2-1')
BEGIN TRANSACTION;
--SELECT top 0 * FROM t WITH (TABLOCKX, HOLDLOCK); -- Lock the table -- Lock the table
--SELECT top 0 * FROM t
delete from t
--insert into t (acname ) values ('2')
WAITFOR DELAY '00:00:12';
insert into t (acname ) values ('2')
COMMIT TRANSACTION;
--rollback
select*from t
drugi query poženeš kot drug user in vidiš, da čakaš ko pa majmune
select*from t
select*from t2
vprašanje niti ni tako neumno samo to so tako robni primeri, da če se bi s takimi stvarmi ukvarjal na trgu bi služil 1e na uro, ok recimo da spada pod učenje
transkcije morajo biti čim krajše časovno: pripraviš tmp tabelo zunaj transkacije, razbiješ na več majhnih transakcij
c3p0 ::
In malo bolj pametni klienti, npr. pri multi-tenant rešitvah, da en "worker" proces dela za nek nabor strank. Sem že videl par 100 ali 1000 workerjev, ki se tepejo za iste podatke in potem sledijo razni deadlocki. Potem pa nikomur nič jasno, če pa so pojačali HW, še vedno pa isti problemi.
DamijanD ::
Je pa zanimivo koliko je razlike med oraclom in mssqlom kar se deadlockov tiče. Isti SW (in podobna uporaba) samo drugi DB provider in na mssqlu pogosto kakšen deadlock v logih, na oraclu pa nobenega. (ima pa Oracle žal druge cvetke)
Malo offtopic ampak vseeno paše v kontekst: Kako bi razvrstili različne DB serverje po "zmogljivosti" (velikost baze, št. sočasnih zahtevkov): oracle, postgree, mssql, DB2?, mariaDB ?
Malo offtopic ampak vseeno paše v kontekst: Kako bi razvrstili različne DB serverje po "zmogljivosti" (velikost baze, št. sočasnih zahtevkov): oracle, postgree, mssql, DB2?, mariaDB ?
Zgodovina sprememb…
- spremenilo: DamijanD ()
Ales ::
... vprašanje niti ni tako neumno ...
@HotBurek, na dan 26.01.2024 si zastavil pametno programersko vprašanje.
Zdaj greš lahko mirne duše v programerska večna lovišča v spremstvu prelepih valkir...
Hm, OK, morda sem pomešal nekaj religij, ampak pri programiranju moraš tako ali tako obvladati cel nabor različnih tehnologij.
Utk ::
Če nekomu prihaja do deadlockov, pa ne ve zakaj, je bolj verjetno problem v njegovi kodi kot v nekem sql serverju. Če pa je problem v sql serverju, programer, ki je prišel do tega limita, bi moral to vedet v čem je problem.
Ponavadi je problem, če imaš neko kodo izven sql-a, ki odpira transakcije, potem pa rabi "pol ure", da naredi svoje, ta čas pa pride drug klient, ki bi rad isto. Tu je navidezno problem v sql-u, ki kao nekaj brez veze zaklepa, ampak v resnici ni, dokler smo v rangu hotbureka, problem je v kodi, ki tisto karkoli že dela, zelo verjetno dela nepotrebno dolgo. Dvomim da ima on neko stored proceduro, ki se izvaja tako dolgo, da bi bil to problem, če pa ima, je verjetno spet problem v proceduri, ki je očitno zanič.
V glavnem...če nekdo to sprašuje in ima problem z locki, bi jaz dal dober denar na to da je problem v njegovi kodi, ne pa v sql serverju.
Ponavadi je problem, če imaš neko kodo izven sql-a, ki odpira transakcije, potem pa rabi "pol ure", da naredi svoje, ta čas pa pride drug klient, ki bi rad isto. Tu je navidezno problem v sql-u, ki kao nekaj brez veze zaklepa, ampak v resnici ni, dokler smo v rangu hotbureka, problem je v kodi, ki tisto karkoli že dela, zelo verjetno dela nepotrebno dolgo. Dvomim da ima on neko stored proceduro, ki se izvaja tako dolgo, da bi bil to problem, če pa ima, je verjetno spet problem v proceduri, ki je očitno zanič.
V glavnem...če nekdo to sprašuje in ima problem z locki, bi jaz dal dober denar na to da je problem v njegovi kodi, ne pa v sql serverju.
Zgodovina sprememb…
- spremenil: Utk ()
HotBurek ::
Pozdravljeni fantje in dekline.
Imam dobro novico. Sem si rekel, da bom bil naredil test, da preverim kaj in kako zadeva dela. In sem ga res.
Naredil sem si testno tabelo, notri pa vnesel nekaj vrstic (id, text). Šel sem tako daleč, da sem postavil primary key na id stolpec, kar kaže, da gre za višji nivo.
Na serverju sem se, kot se za pravega moškega spodobi, povezal v marijo z root accountonm.
In pognal sledeča okuaza:
start stransaction;
delete from table where id = neka cifra;
Potem pa sem na svojem osebnem računalniku, kjer sem z uporabo oddaljenega dostopa povezan na to isto bazo (a z drugim uporabniškim računom), izvedel sledeči napredni ukaz:
select * from table;
In rezultat je, da tabela ni bila zalokana, ter da so notri bili še strai podatki. TOP!
Ko sem na strežniku v ukazni lupini pognal ukaz commit, pa so bili tudi na klientu videni novi podatki.
Prav tako sem preveril vrednost autocommit; ta je bila 1. Kar je pomembno, saj ima klient v configu nastavljeno na autocommit=true.
Well done.
Imam dobro novico. Sem si rekel, da bom bil naredil test, da preverim kaj in kako zadeva dela. In sem ga res.
Naredil sem si testno tabelo, notri pa vnesel nekaj vrstic (id, text). Šel sem tako daleč, da sem postavil primary key na id stolpec, kar kaže, da gre za višji nivo.
Na serverju sem se, kot se za pravega moškega spodobi, povezal v marijo z root accountonm.
In pognal sledeča okuaza:
start stransaction;
delete from table where id = neka cifra;
Potem pa sem na svojem osebnem računalniku, kjer sem z uporabo oddaljenega dostopa povezan na to isto bazo (a z drugim uporabniškim računom), izvedel sledeči napredni ukaz:
select * from table;
In rezultat je, da tabela ni bila zalokana, ter da so notri bili še strai podatki. TOP!
Ko sem na strežniku v ukazni lupini pognal ukaz commit, pa so bili tudi na klientu videni novi podatki.
Prav tako sem preveril vrednost autocommit; ta je bila 1. Kar je pomembno, saj ima klient v configu nastavljeno na autocommit=true.
Well done.
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
Utk ::
Za select ni neke potrebe, da bi tabela lockala. Tabela je stalno v veljavnem stanju, ni razloga, da ne bi smel selectat iz nje. Poskusi namesto selecta pognat update recimo. In to istih vrstic, ki jih brišeš.
Zgodovina sprememb…
- spremenil: Utk ()
c3p0 ::
Malo offtopic ampak vseeno paše v kontekst: Kako bi razvrstili različne DB serverje po "zmogljivosti" (velikost baze, št. sočasnih zahtevkov): oracle, postgree, mssql, DB2?, mariaDB ?
Ne vem ali obstaja absolutni odgovor, pa še kak p/p je treba upoštevat. Glede na cost bi moral Oracle zmagat :). Sam sem sicer biased, ker delam daleč največ s Postgresom v precej large(?) setupih (po 15TB na bazo, ki pa mora zelo hitro delovat).
kuall ::
deadlock se ne bi sam rešil brez pomoči serverja tako, da eno transakcijo ubije. blocking se reši po nekem času sam.
deadlocke se reši tako, da se najde oba problematična queryja in se ju ponovno napiše optimizirano oz vsaj enega. če ni možno pa try catch in v catch če je dedlock še 1x poženemo kodo oz damo flag, da se naslednjič sprocesira.
chatgpt je dober za učenje
explain why here deadlock happens: CREATE TABLE DeadlockTest (
ID INT PRIMARY KEY,
Value INT
);
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
-- SSMS1 zavihek 1
BEGIN TRANSACTION;
UPDATE DeadlockTest SET Value = Value + 10 WHERE ID = 1;
WAITFOR DELAY '00:00:05'; -- Wait for 5 seconds before executing the next query
UPDATE DeadlockTest SET Value = Value + 10 WHERE ID = 2;
-- SSMS2 zavihek 2
BEGIN TRANSACTION;
UPDATE DeadlockTest SET Value = Value - 10 WHERE ID = 2;
WAITFOR DELAY '00:00:05'; -- Wait for 5 seconds before executing the next query
UPDATE DeadlockTest SET Value = Value - 10 WHERE ID = 1;
ChatGPT
The deadlock in your scenario occurs due to a classic case of two transactions acquiring locks on resources in a different order, leading to a deadlock situation.
Let's break down the sequence of events:
SSMS1 (Transaction 1):
Transaction 1 starts by updating the row with ID 1 in the DeadlockTest table, increasing its Value by 10.
This transaction acquires an exclusive lock on the row with ID 1.
SSMS2 (Transaction 2):
Transaction 2 starts by updating the row with ID 2 in the DeadlockTest table, decreasing its Value by 10.
This transaction acquires an exclusive lock on the row with ID 2.
SSMS1 (Transaction 1):
Transaction 1 now tries to update the row with ID 2, increasing its Value by 10.
However, it cannot acquire the exclusive lock on the row with ID 2 because Transaction 2 already holds it.
SSMS2 (Transaction 2):
Transaction 2 tries to update the row with ID 1, decreasing its Value by 10.
However, it cannot acquire the exclusive lock on the row with ID 1 because Transaction 1 already holds it.
Both transactions are now waiting for resources that the other transaction holds, resulting in a deadlock situation. SQL Server automatically detects the deadlock and resolves it by choosing one of the transactions as the deadlock victim and rolling it back.
To avoid deadlocks, it's crucial to ensure that transactions acquire locks on resources in the same order. In this case, you might consider updating rows in a consistent order based on their IDs to prevent deadlocks from occurring. Additionally, you could explore using appropriate isolation levels and transaction handling techniques to minimize the occurrence of deadlocks in your application.
User
other scenarios than updating in different order for deadlock?
ChatGPT
Certainly! Deadlocks can occur due to various scenarios beyond just updating rows in a different order. Here are a few common scenarios:
Insertion Deadlocks: When multiple transactions try to insert rows into the same table simultaneously, they might contend for the same resources and end up deadlocking if they acquire locks on the same resources in a different order.
Index Deadlocks: Deadlocks can occur when transactions try to update or insert rows in a table that requires index modifications. For example, if two transactions need to update different rows but both need to modify the same index, a deadlock can occur if they acquire locks on resources in different orders.
Locking on Non-Clustered Indexes: If queries access the same table but use different non-clustered indexes, they might contend for locks on different index pages, leading to deadlocks.
Cursor Deadlocks: Cursors hold locks on the rows they fetch. If two cursors are opened by different transactions and they try to update rows that the other cursor has locked, a deadlock can occur.
Lock Escalation Deadlocks: In some cases, SQL Server might escalate row-level locks to table-level locks to optimize performance. If multiple transactions are contending for table-level locks and deadlock conditions are met, deadlocks can occur.
Parallelism Deadlocks: Deadlocks can occur in scenarios where multiple parallel queries are executing simultaneously and contend for the same resources.
To prevent deadlocks, it's essential to design transactions and queries carefully, consider the isolation level of transactions, minimize the duration of transactions, and handle exceptions and retries gracefully. Additionally, understanding the application's data access patterns and concurrency requirements can help identify potential deadlock scenarios and mitigate them effectively.
User
give example for 1
ChatGPT
Certainly! Let's consider a scenario where insertion deadlocks can occur:
Suppose we have two transactions executing simultaneously, each trying to insert data into the same table. If both transactions attempt to acquire locks on resources in a different order, a deadlock can occur. Here's an example:
sql
Copy code
-- Transaction 1
BEGIN TRANSACTION;
INSERT INTO MyTable (ID, Name) VALUES (1, 'Transaction 1');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO MyTable (ID, Name) VALUES (2, 'Transaction 1');
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO MyTable (ID, Name) VALUES (2, 'Transaction 2');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO MyTable (ID, Name) VALUES (1, 'Transaction 2');
COMMIT TRANSACTION;
In this scenario:
Transaction 1 starts by inserting a row with ID 1 into MyTable.
Transaction 2 starts by inserting a row with ID 2 into MyTable.
Transaction 1 then attempts to insert a row with ID 2, but it's blocked because Transaction 2 already holds a lock on that row.
Similarly, Transaction 2 attempts to insert a row with ID 1, but it's blocked because Transaction 1 already holds a lock on that row.
Both transactions are waiting for resources that the other transaction holds, resulting in a deadlock. SQL Server detects the deadlock and resolves it by choosing one of the transactions as the deadlock victim and rolling it back.
To avoid insertion deadlocks, it's crucial to ensure that transactions acquire locks on resources in the same order. In this case, you might consider ordering the insertion of rows based on their IDs or using appropriate transaction isolation levels and concurrency control mechanisms to prevent deadlocks from occurring.
User
REWRITE LAST 2 QUERIES TO USE MY TABLE
ChatGPT
Certainly! Here are the last two queries rewritten to use a table named MyTable:
sql
Copy code
-- Transaction 1
BEGIN TRANSACTION;
INSERT INTO MyTable (ID, Name) VALUES (1, 'Transaction 1');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO MyTable (ID, Name) VALUES (2, 'Transaction 1');
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO MyTable (ID, Name) VALUES (2, 'Transaction 2');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO MyTable (ID, Name) VALUES (1, 'Transaction 2');
COMMIT TRANSACTION;
In this script:
Transaction 1 inserts rows with IDs 1 and 2 into MyTable.
Transaction 2 inserts rows with IDs 2 and 1 into MyTable.
Both transactions simulate a delay to illustrate a scenario where deadlock might occur due to contention for the same resources.
The scenario remains the same as described earlier, where if both transactions attempt to acquire locks on resources in a different order, a deadlock can occur.
User
NO, USE MY TABLE DeadlockTest
ChatGPT
Apologies for the oversight. Here are the last two queries rewritten to use the DeadlockTest table:
sql
Copy code
-- Transaction 1
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 'Transaction 1');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 'Transaction 1');
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 'Transaction 2');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 'Transaction 2');
COMMIT TRANSACTION;
In this script:
Transaction 1 inserts rows with IDs 1 and 2 into DeadlockTest.
Transaction 2 inserts rows with IDs 2 and 1 into DeadlockTest.
Both transactions simulate a delay to illustrate a scenario where deadlock might occur due to contention for the same resources.
The scenario remains the same as described earlier, where if both transactions attempt to acquire locks on resources in a different order, a deadlock can occur.
User
value should be int!!
ChatGPT
Apologies for the oversight. Let me correct that for you. Here are the queries rewritten with the Value column as an INT type:
sql
Copy code
-- Transaction 1
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
COMMIT TRANSACTION;
In this script:
Transaction 1 inserts rows with IDs 1 and 2 into DeadlockTest.
Transaction 2 inserts rows with IDs 2 and 1 into DeadlockTest.
Both transactions simulate a delay to illustrate a scenario where deadlock might occur due to contention for the same resources.
If both transactions attempt to acquire locks on resources in a different order, a deadlock can occur.
User
thats ok just need truncate table DeadlockTest in transaction 1
ChatGPT
Understood. Here's the revised version of the transactions, where Transaction 1 truncates the DeadlockTest table:
sql
Copy code
-- Transaction 1
BEGIN TRANSACTION;
TRUNCATE TABLE DeadlockTest; -- Truncate the table
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
COMMIT TRANSACTION;
In this script:
Transaction 1 starts by truncating the DeadlockTest table to remove all existing records.
It then proceeds to insert new rows with IDs 1 and 2 into DeadlockTest.
Transaction 2 inserts rows with IDs 2 and 1 into DeadlockTest.
Both transactions simulate a delay to illustrate a scenario where deadlock might occur due to contention for the same resources.
If both transactions attempt to acquire locks on resources in a different order, a deadlock can occur.
User
better to put it out ot transaction
ChatGPT
Certainly, if the truncation of the table doesn't need to be part of the transaction, it's better to perform it outside the transaction to reduce the likelihood of deadlocks and improve concurrency. Here's how you can modify the script:
sql
Copy code
-- Truncate the table outside of the transaction
TRUNCATE TABLE DeadlockTest;
-- Transaction 1
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
COMMIT TRANSACTION;
In this script:
The TRUNCATE TABLE DeadlockTest; statement truncates the DeadlockTest table outside of any transaction.
Transaction 1 and Transaction 2 proceed with their inserts without performing any table truncation.
Both transactions simulate a delay to illustrate a scenario where deadlock might occur due to contention for the same resources.
By removing the table truncation from the transaction, you reduce the likelihood of conflicts and deadlocks, especially in scenarios where multiple transactions are accessing the same table concurrently.
deadlocke se reši tako, da se najde oba problematična queryja in se ju ponovno napiše optimizirano oz vsaj enega. če ni možno pa try catch in v catch če je dedlock še 1x poženemo kodo oz damo flag, da se naslednjič sprocesira.
chatgpt je dober za učenje
explain why here deadlock happens: CREATE TABLE DeadlockTest (
ID INT PRIMARY KEY,
Value INT
);
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
-- SSMS1 zavihek 1
BEGIN TRANSACTION;
UPDATE DeadlockTest SET Value = Value + 10 WHERE ID = 1;
WAITFOR DELAY '00:00:05'; -- Wait for 5 seconds before executing the next query
UPDATE DeadlockTest SET Value = Value + 10 WHERE ID = 2;
-- SSMS2 zavihek 2
BEGIN TRANSACTION;
UPDATE DeadlockTest SET Value = Value - 10 WHERE ID = 2;
WAITFOR DELAY '00:00:05'; -- Wait for 5 seconds before executing the next query
UPDATE DeadlockTest SET Value = Value - 10 WHERE ID = 1;
ChatGPT
The deadlock in your scenario occurs due to a classic case of two transactions acquiring locks on resources in a different order, leading to a deadlock situation.
Let's break down the sequence of events:
SSMS1 (Transaction 1):
Transaction 1 starts by updating the row with ID 1 in the DeadlockTest table, increasing its Value by 10.
This transaction acquires an exclusive lock on the row with ID 1.
SSMS2 (Transaction 2):
Transaction 2 starts by updating the row with ID 2 in the DeadlockTest table, decreasing its Value by 10.
This transaction acquires an exclusive lock on the row with ID 2.
SSMS1 (Transaction 1):
Transaction 1 now tries to update the row with ID 2, increasing its Value by 10.
However, it cannot acquire the exclusive lock on the row with ID 2 because Transaction 2 already holds it.
SSMS2 (Transaction 2):
Transaction 2 tries to update the row with ID 1, decreasing its Value by 10.
However, it cannot acquire the exclusive lock on the row with ID 1 because Transaction 1 already holds it.
Both transactions are now waiting for resources that the other transaction holds, resulting in a deadlock situation. SQL Server automatically detects the deadlock and resolves it by choosing one of the transactions as the deadlock victim and rolling it back.
To avoid deadlocks, it's crucial to ensure that transactions acquire locks on resources in the same order. In this case, you might consider updating rows in a consistent order based on their IDs to prevent deadlocks from occurring. Additionally, you could explore using appropriate isolation levels and transaction handling techniques to minimize the occurrence of deadlocks in your application.
User
other scenarios than updating in different order for deadlock?
ChatGPT
Certainly! Deadlocks can occur due to various scenarios beyond just updating rows in a different order. Here are a few common scenarios:
Insertion Deadlocks: When multiple transactions try to insert rows into the same table simultaneously, they might contend for the same resources and end up deadlocking if they acquire locks on the same resources in a different order.
Index Deadlocks: Deadlocks can occur when transactions try to update or insert rows in a table that requires index modifications. For example, if two transactions need to update different rows but both need to modify the same index, a deadlock can occur if they acquire locks on resources in different orders.
Locking on Non-Clustered Indexes: If queries access the same table but use different non-clustered indexes, they might contend for locks on different index pages, leading to deadlocks.
Cursor Deadlocks: Cursors hold locks on the rows they fetch. If two cursors are opened by different transactions and they try to update rows that the other cursor has locked, a deadlock can occur.
Lock Escalation Deadlocks: In some cases, SQL Server might escalate row-level locks to table-level locks to optimize performance. If multiple transactions are contending for table-level locks and deadlock conditions are met, deadlocks can occur.
Parallelism Deadlocks: Deadlocks can occur in scenarios where multiple parallel queries are executing simultaneously and contend for the same resources.
To prevent deadlocks, it's essential to design transactions and queries carefully, consider the isolation level of transactions, minimize the duration of transactions, and handle exceptions and retries gracefully. Additionally, understanding the application's data access patterns and concurrency requirements can help identify potential deadlock scenarios and mitigate them effectively.
User
give example for 1
ChatGPT
Certainly! Let's consider a scenario where insertion deadlocks can occur:
Suppose we have two transactions executing simultaneously, each trying to insert data into the same table. If both transactions attempt to acquire locks on resources in a different order, a deadlock can occur. Here's an example:
sql
Copy code
-- Transaction 1
BEGIN TRANSACTION;
INSERT INTO MyTable (ID, Name) VALUES (1, 'Transaction 1');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO MyTable (ID, Name) VALUES (2, 'Transaction 1');
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO MyTable (ID, Name) VALUES (2, 'Transaction 2');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO MyTable (ID, Name) VALUES (1, 'Transaction 2');
COMMIT TRANSACTION;
In this scenario:
Transaction 1 starts by inserting a row with ID 1 into MyTable.
Transaction 2 starts by inserting a row with ID 2 into MyTable.
Transaction 1 then attempts to insert a row with ID 2, but it's blocked because Transaction 2 already holds a lock on that row.
Similarly, Transaction 2 attempts to insert a row with ID 1, but it's blocked because Transaction 1 already holds a lock on that row.
Both transactions are waiting for resources that the other transaction holds, resulting in a deadlock. SQL Server detects the deadlock and resolves it by choosing one of the transactions as the deadlock victim and rolling it back.
To avoid insertion deadlocks, it's crucial to ensure that transactions acquire locks on resources in the same order. In this case, you might consider ordering the insertion of rows based on their IDs or using appropriate transaction isolation levels and concurrency control mechanisms to prevent deadlocks from occurring.
User
REWRITE LAST 2 QUERIES TO USE MY TABLE
ChatGPT
Certainly! Here are the last two queries rewritten to use a table named MyTable:
sql
Copy code
-- Transaction 1
BEGIN TRANSACTION;
INSERT INTO MyTable (ID, Name) VALUES (1, 'Transaction 1');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO MyTable (ID, Name) VALUES (2, 'Transaction 1');
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO MyTable (ID, Name) VALUES (2, 'Transaction 2');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO MyTable (ID, Name) VALUES (1, 'Transaction 2');
COMMIT TRANSACTION;
In this script:
Transaction 1 inserts rows with IDs 1 and 2 into MyTable.
Transaction 2 inserts rows with IDs 2 and 1 into MyTable.
Both transactions simulate a delay to illustrate a scenario where deadlock might occur due to contention for the same resources.
The scenario remains the same as described earlier, where if both transactions attempt to acquire locks on resources in a different order, a deadlock can occur.
User
NO, USE MY TABLE DeadlockTest
ChatGPT
Apologies for the oversight. Here are the last two queries rewritten to use the DeadlockTest table:
sql
Copy code
-- Transaction 1
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 'Transaction 1');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 'Transaction 1');
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 'Transaction 2');
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 'Transaction 2');
COMMIT TRANSACTION;
In this script:
Transaction 1 inserts rows with IDs 1 and 2 into DeadlockTest.
Transaction 2 inserts rows with IDs 2 and 1 into DeadlockTest.
Both transactions simulate a delay to illustrate a scenario where deadlock might occur due to contention for the same resources.
The scenario remains the same as described earlier, where if both transactions attempt to acquire locks on resources in a different order, a deadlock can occur.
User
value should be int!!
ChatGPT
Apologies for the oversight. Let me correct that for you. Here are the queries rewritten with the Value column as an INT type:
sql
Copy code
-- Transaction 1
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
COMMIT TRANSACTION;
In this script:
Transaction 1 inserts rows with IDs 1 and 2 into DeadlockTest.
Transaction 2 inserts rows with IDs 2 and 1 into DeadlockTest.
Both transactions simulate a delay to illustrate a scenario where deadlock might occur due to contention for the same resources.
If both transactions attempt to acquire locks on resources in a different order, a deadlock can occur.
User
thats ok just need truncate table DeadlockTest in transaction 1
ChatGPT
Understood. Here's the revised version of the transactions, where Transaction 1 truncates the DeadlockTest table:
sql
Copy code
-- Transaction 1
BEGIN TRANSACTION;
TRUNCATE TABLE DeadlockTest; -- Truncate the table
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
COMMIT TRANSACTION;
In this script:
Transaction 1 starts by truncating the DeadlockTest table to remove all existing records.
It then proceeds to insert new rows with IDs 1 and 2 into DeadlockTest.
Transaction 2 inserts rows with IDs 2 and 1 into DeadlockTest.
Both transactions simulate a delay to illustrate a scenario where deadlock might occur due to contention for the same resources.
If both transactions attempt to acquire locks on resources in a different order, a deadlock can occur.
User
better to put it out ot transaction
ChatGPT
Certainly, if the truncation of the table doesn't need to be part of the transaction, it's better to perform it outside the transaction to reduce the likelihood of deadlocks and improve concurrency. Here's how you can modify the script:
sql
Copy code
-- Truncate the table outside of the transaction
TRUNCATE TABLE DeadlockTest;
-- Transaction 1
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
COMMIT TRANSACTION;
-- Transaction 2
BEGIN TRANSACTION;
INSERT INTO DeadlockTest (ID, Value) VALUES (2, 200);
WAITFOR DELAY '00:00:05'; -- Simulate a delay
INSERT INTO DeadlockTest (ID, Value) VALUES (1, 100);
COMMIT TRANSACTION;
In this script:
The TRUNCATE TABLE DeadlockTest; statement truncates the DeadlockTest table outside of any transaction.
Transaction 1 and Transaction 2 proceed with their inserts without performing any table truncation.
Both transactions simulate a delay to illustrate a scenario where deadlock might occur due to contention for the same resources.
By removing the table truncation from the transaction, you reduce the likelihood of conflicts and deadlocks, especially in scenarios where multiple transactions are accessing the same table concurrently.
no comment ::
HotBurek ::
Gre za cache search rezultatov.
Npr. za key "test" so rezultati:
test - 0095 - 11.20
test - 0003 - 7.41
test - 0061 - 5.50
In te rezultate se zapiše v cache tabelo.
S časoma se v source tabeli dodajo novi zapisi, ki vsebujejo key "test". In ko se ponovno zgenerirajo search rezultati za key "test", pride ven:
test - 0095 - 11.20
test - 0104 - 9.18
test - 0003 - 7.31
test - 0061 - 5.50
Sedaj je potrebno dodad 0104 v cache tabelo za kej "test".
Kasneje, se ponovi zgodba, notri v source tabelo pridejo novi zapisi, ki vsebujejo key "test", in spet se naredi update search rezultatov:
test - 0155 - 18.18
test - 0095 - 11.20
test - 0104 - 9.18
test - 0003 - 7.31
test - 0061 - 5.50
V tem primeru je potrebno v cache tabelo dodati nov element 0155.
Mogoče bi šlo takšen "update" naredit bolj elegantno, kot DELETE + INSERT.
-------------
Zdaj razmišljam. Težava je, da ko iz source tabele dobiš rezultate, bi pred vnosom moral za vsak id preverit, če že obstaja v cache tabeli. In če ne obstaja, bi ga insertal.
Istočasno je potrebno preverit, kolikšen je max match value za key, in tiste ki imajo premajhen match value, sploh ne vnest v tabelo.
Npr. za key "test" so rezultati:
test - 0095 - 11.20
test - 0003 - 7.41
test - 0061 - 5.50
In te rezultate se zapiše v cache tabelo.
S časoma se v source tabeli dodajo novi zapisi, ki vsebujejo key "test". In ko se ponovno zgenerirajo search rezultati za key "test", pride ven:
test - 0095 - 11.20
test - 0104 - 9.18
test - 0003 - 7.31
test - 0061 - 5.50
Sedaj je potrebno dodad 0104 v cache tabelo za kej "test".
Kasneje, se ponovi zgodba, notri v source tabelo pridejo novi zapisi, ki vsebujejo key "test", in spet se naredi update search rezultatov:
test - 0155 - 18.18
test - 0095 - 11.20
test - 0104 - 9.18
test - 0003 - 7.31
test - 0061 - 5.50
V tem primeru je potrebno v cache tabelo dodati nov element 0155.
Mogoče bi šlo takšen "update" naredit bolj elegantno, kot DELETE + INSERT.
-------------
Zdaj razmišljam. Težava je, da ko iz source tabele dobiš rezultate, bi pred vnosom moral za vsak id preverit, če že obstaja v cache tabeli. In če ne obstaja, bi ga insertal.
Istočasno je potrebno preverit, kolikšen je max match value za key, in tiste ki imajo premajhen match value, sploh ne vnest v tabelo.
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
FireSnake ::
To, kar zgoraj pišeš je idiotija! Iz tehničnega vidika možgansko bruhanje brez repa in glave.
Ti pa zanič! Ker bi moral to vedeti preden si se sploh usedel za računalnik.
Deadlocke še v šoli učijo.
deadlock se ne bi sam rešil brez pomoči serverja tako, da eno transakcijo ubije. blocking se reši po nekem času sam.
deadlocke se reši tako, da se najde oba problematična queryja in se ju ponovno napiše optimizirano oz vsaj enega. če ni možno pa try catch in v catch če je dedlock še 1x poženemo kodo oz damo flag, da se naslednjič sprocesira.
chatgpt je dober za učenje
Ti pa zanič! Ker bi moral to vedeti preden si se sploh usedel za računalnik.
Deadlocke še v šoli učijo.
Poglej in se nasmej: vicmaher.si
Zgodovina sprememb…
- spremenilo: FireSnake ()
Lonsarg ::
Deadlock je izključno programerska napaka in sicer če dve transakcija v različnem vrstnem redu zaklepata tabele ali isto vrstico tabele.
Ena hitr hack je tisto tabelo na katero dobiš deadlock prestaviti na vrh transakcije in narediti select z "WITH LOCK" (no vsaj MS SQL ima tako, ampak koncepti so pri vseh bazah podobni, tudi Oracle ni nobena izjema sam sintakso ima precej drugačno, skratka povsod se da eksplicitno z rpvim querijem v transakciji določeno celo tabelo zaklenit). Če namreč dve transakciji obe v prvem ukazu isto tabelo lockata to nikoli ne bo deadlock, ampak bo ena izmed transakcij počakala na drugo.
Ampak to je seveda hack, ker s tem si omejil izvajanje te transakcije na en thread in to v marsikaterem primeru ni performančno ok. Proper rešitve so pa case by case. Recimo ko govorimo o problemih ko dve transakcije potencialno isti ID/row dotikata ampak je processing dejansko zgolj per ta ID se to reši z softwerskimi eksplicitnimi locki, da pač procesing logiko zakleneš na max en thread per ID (rešitev kako to narediti je ogromno različnih, lahko SQL, lahko iz top level kode v .net,...). Ko tako pametno vsebinsko zakleneš procesing ti je potem vseeno če je transakcija malo večja (včasih, zorioma rpavzaprav zelo pogosto pač esplicitno hočeš cel procesing v transakcijo dat, tudi tak ki dotika potencialno veliko tabel, več SQL procedur itd), dokler vsebinsko dotika zgolj določene vrstice vezane na ta ID. Tudi performančno je ta rešitev top, ker imaš omejeno per en thread per ID še vedno pa neomejeno threadov med različnimi IDji.
V primeru MS SQL za softwerski eksplicitni per ID lock mi uporabljamo https://learn.microsoft.com/en-us/sql/r..., ne glede na to ali je iz .net ali SQL kode. Ko več aplikacij isto pogodbo obdelava si ta ID sharajo in tako elegantno rešimo deadlocke in lahko vse aplikacije per pogodba procesing delajo v eni transakciji ne glede na to koliko dolg je ta procesing, še pošiljanje preko integracij in APIjev je znotraj te transakcije.
Ena hitr hack je tisto tabelo na katero dobiš deadlock prestaviti na vrh transakcije in narediti select z "WITH LOCK" (no vsaj MS SQL ima tako, ampak koncepti so pri vseh bazah podobni, tudi Oracle ni nobena izjema sam sintakso ima precej drugačno, skratka povsod se da eksplicitno z rpvim querijem v transakciji določeno celo tabelo zaklenit). Če namreč dve transakciji obe v prvem ukazu isto tabelo lockata to nikoli ne bo deadlock, ampak bo ena izmed transakcij počakala na drugo.
Ampak to je seveda hack, ker s tem si omejil izvajanje te transakcije na en thread in to v marsikaterem primeru ni performančno ok. Proper rešitve so pa case by case. Recimo ko govorimo o problemih ko dve transakcije potencialno isti ID/row dotikata ampak je processing dejansko zgolj per ta ID se to reši z softwerskimi eksplicitnimi locki, da pač procesing logiko zakleneš na max en thread per ID (rešitev kako to narediti je ogromno različnih, lahko SQL, lahko iz top level kode v .net,...). Ko tako pametno vsebinsko zakleneš procesing ti je potem vseeno če je transakcija malo večja (včasih, zorioma rpavzaprav zelo pogosto pač esplicitno hočeš cel procesing v transakcijo dat, tudi tak ki dotika potencialno veliko tabel, več SQL procedur itd), dokler vsebinsko dotika zgolj določene vrstice vezane na ta ID. Tudi performančno je ta rešitev top, ker imaš omejeno per en thread per ID še vedno pa neomejeno threadov med različnimi IDji.
V primeru MS SQL za softwerski eksplicitni per ID lock mi uporabljamo https://learn.microsoft.com/en-us/sql/r..., ne glede na to ali je iz .net ali SQL kode. Ko več aplikacij isto pogodbo obdelava si ta ID sharajo in tako elegantno rešimo deadlocke in lahko vse aplikacije per pogodba procesing delajo v eni transakciji ne glede na to koliko dolg je ta procesing, še pošiljanje preko integracij in APIjev je znotraj te transakcije.
Zgodovina sprememb…
- spremenil: Lonsarg ()
Vredno ogleda ...
Tema | Ogledi | Zadnje sporočilo | |
---|---|---|---|
Tema | Ogledi | Zadnje sporočilo | |
» | Mariadb (InnoDB) istočasni insert v tabelo iz različnih procesov (strani: 1 2 )Oddelek: Programiranje | 7283 (3641) | 2g00d4u |
» | [SQL] primary key inkrementalno dodajanje (strani: 1 2 )Oddelek: Programiranje | 5354 (4544) | ejresnevem |
» | Nova različica podatkovne baze PostgreSQL 9.5 prinaša obilico novosti (strani: 1 2 )Oddelek: Novice / Ostala programska oprema | 17554 (14420) | McAjvar |
» | c# - mssql kombinacija / problem pri zapisu row-a v bazoOddelek: Programiranje | 1590 (1399) | darkolord |
» | SQL trigger OracleOddelek: Programiranje | 1168 (1076) | PunXXX |