Jag fick nyligen en fråga om varför man inte skulle köra transaktionshantering på alla insert, delete och updates. Jag svarade att det kräver mer overhead att köra transaktionshantering på allt och detta kan i sin tur påverka prestandan. Som jag förstått det så låser transaktionshanteringen den eller de specifika tabeller man jobbar med tills transaktionen blivit godkänd (eller "underkänd/rollback"). Att ha transaktioner kring ett enda anrop a la: Om du gör en en-rads operation typ en liten UPDATE så kommer det automatiskt skapas en transaktion runt den. Nåt annat vore ju orimligt. DBMS måste se till att data som skrivs blir korrekt. T.ex att inte två användare skriver på samma rad samtidigt! Det innebär också att det i regel är helt onödigt att skriva BEGIN TRAN osv i de flesta vanliga updates. Men transaktioner används ändå. T.ex. PostgreSQL låser inte, den skapar bara nytt. Beroende på transaktionstyp så tror jag att man kan välja hur mycket andra ser innan en transaktion är commitad. Vitsen är att eftersom att ingenting behöver låsas så hindras ingen annan att läsa data. Sedan kan jag inte detaljerna i det, men det är någonting sådant. Jag gjorde nu ett test på SQL Servern med följande kod: Dock.. Det finns olika varianter av transaktioner Krister: Ja, men det innebär inte att INSERT alltid låser hela tabellen. Krister:Transaktionshantering (ADO.NET) på alla insert, delete och updates
Svaret jag fick var att detta inte är sant i tex Oracle. Då blev jag lite osäker men även om man inte låser tabellen så kommer det ha någon inverkan som tex att transaktionsloggen blir större.
Min åsikt är den att rent generellt så använder man transaktionshantering på (speciellt kritiska) flöden, dvs där tex flera insert-satser måste lyckas för att transaktionen ska anses som godkänd. Det finns ingen mening att köra transaktionshantering på enskilda sql-satser för smäller det då har transaktionen ändå inte genomförts därför kommer aldrig rollback aldrig göras.
Vad tycker ni? Är det något som ni inte håller med om?Sv: Transaktionshantering (ADO.NET) på alla insert, delete och updates
db.BeginTransaction
db.Insert(...)
db.CommitTransaction
Kan jag inte se en enda nytta med det, givet att databasen uppfyller ACID-kraven.
Å andra sidan är det så att de flesta databaser inte låser hela tabeller, utan bara delar av dem, eller hanterar icke commitade och commitade data på olika sätt (jag har för mig att isolation levels bara ställer lägsta-krav; att man får vara mer isolerad men inte mindre), så performance-penaltyn borde vara ganska låg. Titta till exempel på "optimistic locking". Sv: Transaktionshantering (ADO.NET) på alla insert, delete och updates
Du kan verifiera detta genom att köra:
SET IMPLICIT_TRANSACTIONS ON
UPDATE MyTable
SET [Txt] = 'CCC' WHERE ID = 1
-- testa.. ingen update..
-- du måste nu skriva COMMIT TRAN för att det ska bli någon update.
Vad som blir låst vid en UPDATE beror på hur din SQL och dina Index ser ut. Har du en vettig primärnyckel och villkorar på denna i din UPDATE så kommer en transaktion skapas som låser endast en rad. Om du däremot skriver en update utan någon WHERE (alltså uppdatera alla rader) så måste den ju låsa hela tabellen vid skrivningen. Likadant om du inte har någon primärnyckel, då kan inte DB veta på förhand hur mycket som skall låsas och du riskerar att låsa hela tabellen. Läs mer om Lock Escalation: http://sqlthoughts.blogspot.com/2008/08/lock-escalation-in-sql-server-2005.htmlSv: Transaktionshantering (ADO.NET) på alla insert, delete och updates
Sv:Transaktionshantering (ADO.NET) på alla insert, delete och updates
SET IMPLICIT_TRANSACTIONS ON
INSERT INTO MinTabell (MinKolumn) VALUES ('blabla')
WAITFOR DELAY '00:00:10' -- Vänta i 10 sekunder innan commit
COMMIT TRAN
Jag bad en kollega göra en simpel select-sats mot min tabell medan jag körde transaktionen ovan. Det som inträffade var att han fick vänta i 10 sekunder innan han fick resultatet. Körde han select-satsen utan att min transaktion då fick han resultatet direkt. Så i detta fallet låser man tabellen.Sv: Transaktionshantering (ADO.NET) på alla insert, delete och updates
Sv: Transaktionshantering (ADO.NET) på alla insert, delete och updates
I detta fall valdes Table Lock antagligen pga att det saknades index eller att frågan ändå skulle påverka hela tabellen (vilket är sant om du gör en INSERT i en tabell utan data). Du kan se vilka locks du får med sp_locks. För att kunna göra några bra tester bör du ha en tabell med några tusen rader iaf.Sv: Transaktionshantering (ADO.NET) på alla insert, delete och updates
Din fråga låser inte hela tabellen utan bara en del av den, men din kompis SELECT går igenom hela din tabell, även den låsta delen. Så därför står den och väntar tills din transaktion är klar. Om din tabell är indexerad så kan SELECT använda sig av indexet och på så sätt se att den inte behöver den låsta delen och då behöver den inte vänta. Om du vill inserta data och även kunna läsa samtidigt så kan du köra isolation level READ UNCOMMITTED.
Mvh Fredrik Normén
ASP.Net MVP MCT MEET ASPInsider
http://weblogs.asp.net/fredriknormen