I looked at all the isolation types.
But I could not find the mode I wanted.
It can be read by other transaction during the transaction.
But, it will not add update and delete data.
For example (pseudo code):
create table abc
(id uniqueidentifier primary key)
Create proc procMain
trans isolation level **??????**
insert abc (id) values (newid())
Waiting 10 minute
commit
Create proc procREAD
select * from abc
Create proc procAdd
insert abc (id) values (newid())
create proc procUpdate
update abc id = newid()
create proc procDelete
delete from abc
now;
exec procMain (abc table access read only and for other access: LOCKED)
(waiting...)
exec procRead (OK) (Readable)
exec procAdd (NO - never) (locked)
exec procUpdate (NO - never) (locked)
exec procDelete (NO - never) (locked)
Thanks...
Is there such an isolation level? (transaction isolation level?)
Sort of. If you set the READ COMMITTED SNAPSHOT database setting then READ COMMITTED sessions will not be blocked by in-flight transactions. But they will see the "last-known-good" version of the rows, ie the state before the current transaction started.
David
You're looking for READ UNCOMMITTED. Learn more here. Pay mind that this will lead to dirty reads.
Related
I need to answer two questions. Here's an overview:
I have 3 tables:
CREATE TABLE A(x INT)
CREATE TABLE B(x INT)
CREATE TABLE C(x INT)
and 2 triggers:
ALTER TRIGGER ATr ON A
FOR INSERT AS
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
INSERT INTO B
SELECT *
FROM inserted;
COMMIT
END
ALTER TRIGGER BTr ON B
FOR INSERT AS
BEGIN
INSERT INTO C
SELECT * FROM inserted;
END
and the INSERT triggering the ATr trigger INSERT INTO A VALUES(3) is done on REPEATABLE READ isolation level, and the default isolation level for this database is READ COMMITTED.
And I need to answer two questions:
On which isolation level will the ATr trigger execute?
On which isolation level will the BTr trigger execute (if at all)?
I have problem understanding how these nested transactions are going to work. Will any transaction inside a LEVEL SERIALIZABLE transaction ever execute? Are they even nested in this case? What happens if a lower isolation level is inside a higher isolation level or the other way around?
The behavior is documented here SET TRANSACTION ISOLATION LEVEL
And you can examine this behavior by running
select CASE transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'ReadUncomitted'
WHEN 2 THEN 'ReadCommitted'
WHEN 3 THEN 'Repeatable'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot' END AS transaction_isolation_level
from sys.dm_exec_requests
where session_id = ##spid
wherever you are curious about the currently-active isolation level.
I've been reading the MSDN about transaction isolation levels and table hints in an effort to find out what I need to do to exclusively lock a table while I perform a 2 step insert in SQL Server. I've come up with 2 ways to do it and would like to know what the difference is between the approaches.
This answer shows how to do it with hints (https://stackoverflow.com/a/23759307/545430):
--Enclose steps in transaction to define an atomic operation
BEGIN TRAN
-- Perform an insert that locks tblMoo
INSERT INTO tblMoo SET fldCow='valPie' WITH (TABLOCKX, SERIALIZABLE)
UPDATE tblMoo SET fldCowIndex=(SELECT MAX(fldCowIndex) + 1)
COMMIT TRAN
I think I could also achieve my objective by setting the isolation level:
BEGIN TRAN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
INSERT blah blah blah
UPDATE hoo dee dah
COMMIT TRAN
It is important that I lock the entire table from any updates while my transaction is inserting this new row. Would both approaches yield the same result: the table being locked for both the INSERT and UPDATE commands?
I created a database called 'test_isolation' and created a table 'person' with data
name age
---- ---
test1 1
test2 2
test3 3
test4 4
test5 5
test6 6
Now the database is altered to allow snapshot isolation in session1
ALTER DATABASE test_isolation
SET ALLOW_SNAPSHOT_ISOLATION ON
GO
Now I create a transaction in session 2
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
GO
BEGIN TRAN
SELECT * FROM PERSON
GO
DELETE FROM PERSON WHERE name = 'test6'
GO
SELECT * FROM PERSON
GO
The results are as expected. (Note we haven't committed this transaction yet!)
Now I execute the following query in session 3
SELECT * FROM PERSON
The query in session 3 keeps on running infinitely which means the table is locked.
If I go back to session 2 and commit the transaction.. I'm able to run the query on session 3 and the results are as expected.
Transaction isolation level SNAPSHOT is not supposed lock the table right? Am I doing something wrong or my understanding of transaction SNAPSHOT isolation is wrong?
Please help..
You must explicitly declare SET TRANSACTION ISOLATION LEVEL SNAPSHOT in session three, otherwise session 3 will still operate as READ_COMMITTED and block on the update.
This option can also be set at the database level to replace READ_COMMITTED with SNAPSHOT.
ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON
My test table:
CREATE TABLE [dbo].[Personel](
[PersonelID] [int] NOT NULL,
[Name] [nchar](10) NULL,
CONSTRAINT [PK_Personel] PRIMARY KEY CLUSTERED
(
[PersonelID] ASC
)
)
My Test Data:
insert into Personel
values (1, 'Jack')
, (2, 'John')
, (3, 'Kevin')
Connection A:
begin tran
update Personel
set Name = 'Michael'
where PersonelID = 1
Connection B:
SET TRANSACTION ISOLATION LEVEL ????
SELECT Name
FROM Personel WITH (????)
where PersonelID = 1
Connection A starts a transaction and is trying to update data, but transaction is still going on. Connection B tries to read the data that is being updated.
Is there a way (an Isolation Level or a hint or combination of these two) to see the original data (Jack, not Michael) before the transaction is committed or rolled back?
You can access the old version of the data in the SNAPSHOT isolation level.
This requires that the database has snapshot isolation enabled before you start:
ALTER DATABASE <dbname> SET ALLOW_SNAPSHOT_ISOLATION ON
Then in connection B
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
select * from Personel
There are some performance considerations with snapshot isolation, because it duplicates the rows read into tempdb.
Documentation reference
SNAPSHOT (aka. row versioning).
Under snapshot isolation the connection B will see the data as-it-was when ti started the transaction in connection B (even if you did not start an explicit transaction, there is an implicit transaction started by the SELECT statement). See Understanding Row Versioning-Based Isolation Levels:
Read operations performed by a snapshot transaction retrieve the last
version of each row that had been committed at the time the snapshot
transaction started.
SNAPSHOT support must be explictly enabled in teh database:
ALTER DATABASE <DatabaseName> SET ALLOW_SNAPSHOT_ISOLATION ON;
Should I run
ALTER DATABASE DbName SET ALLOW_SNAPSHOT_ISOLATION OFF
if snapshot transaction (TX) isolation (iso) is not temporarily used?
In other words,
why should it be enabled, in first place?
Why isn't it enabled by default?
What is the cost of having it enabled (but temporarily not used) in SQL Server?
--Update:
enabling of snapshot TX iso level on database does not change READ COMMITTED tx iso to be default.
You may check it by running:
use someDbName;
--( 1 )
alter database someDbName set allow_snapshot_isolation ON;
dbcc useroptions;
the last row shows that tx iso level of current session is (read committed).
So, enabling snapshot tx iso level without changing to it does not use it, etc
In order to use it one should issue
--( 2 )
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
Update2:
I repeat the scripts from [1] but with SNAPSHOT enabled (but not switched on) but without enabling READ_COMMITTED_SNAPSHOT
--with enabling allow_snapshot_isolation
alter database snapshottest set allow_snapshot_isolation ON
-- but without enabling read_committed_snapshot
--alter database snapshottest set read_committed_snapshot ON
-- OR with OFF
alter database snapshottest set read_committed_snapshot OFF
go
There no results/rows from from executing
select * from sys.dm_tran_version_store
after executing INSERT, DELETE or UPDATE
Can you provide me with scripts illustrating that enabled SNAPSHOT tx iso level by ( 1 ) but not switched on by ( 2 ) produces any versions in tempdb and/or increase the size of data with 14 bytes per row?
Really I do not understand what is the point in versioning if it is enabled by ( 1 ) but not used (not set on by ( 2))?
[1]
Managing TempDB in SQL Server: TempDB Basics (Version Store: Simple Example)
Link
As soon as row versioning (aka. snapshot) is enabled in the database all writes have to be versioned. It doesn't matter under what isolation level the write occurred, since isolation levels always affect only reads. As soon the database row versioning is enabled, any insert/update/delete will:
increase the size of data with 14 bytes per row
possibly create an image of the data before the update in the version store (tempdb)
Again, it is completely irrelevant what isolation level is used. Note that row versioning occurs also if any of the following is true:
table has a trigger
MARS is enabled on the connection
Online index operation is running on the table
All this is explained in Row Versioning Resource Usage:
Each database row may use up to 14
bytes at the end of the row for row
versioning information. The row
versioning information contains the
transaction sequence number of the
transaction that committed the version
and the pointer to the versioned row.
These 14 bytes are added the first
time the row is modified, or when a
new row is inserted, under any
of these conditions:
READ_COMMITTED_SNAPSHOT or ALLOW_SNAPSHOT_ISOLATION options are
ON.
The table has a trigger.
Multiple Active Results Sets (MARS) is being used.
Online index build operations are currently running on the table.
...
Row versions must be stored for as
long as an active transaction needs to
access it. ... if it meets any of the
following conditions:
It uses row versioning-based isolation.
It uses triggers, MARS, or online index build operations.
It generates row versions.
Update
:setvar dbname testsnapshot
use master;
if db_id('$(dbname)') is not null
begin
alter database [$(dbname)] set single_user with rollback immediate;
drop database [$(dbname)];
end
go
create database [$(dbname)];
go
use [$(dbname)];
go
-- create a table before row versioning is enabled
--
create table t1 (i int not null);
go
insert into t1(i) values (1);
go
-- this check will show that the records do not contain a version number
--
select avg_record_size_in_bytes
from sys.dm_db_index_physical_stats (db_id(), object_id('t1'), NULL, NULL, 'DETAILED')
-- record size: 11 (lacks version info that is at least 14 bytes)
-- enable row versioning and and create an identical table
--
alter database [$(dbname)] set allow_snapshot_isolation on;
go
create table t2 (i int not null);
go
set transaction isolation level read committed;
go
insert into t2(i) values (1);
go
-- This check shows that the rows in t2 have version number
--
select avg_record_size_in_bytes
from sys.dm_db_index_physical_stats (db_id(), object_id('t2'), NULL, NULL, 'DETAILED')
-- record size: 25 (11+14)
-- this update will show that the version store has records
-- even though the isolation level is read commited
--
begin transaction;
update t1
set i += 1;
select * from sys.dm_tran_version_store;
commit;
go
-- And if we check again the row size of t1, its rows now have a version number
select avg_record_size_in_bytes
from sys.dm_db_index_physical_stats (db_id(), object_id('t1'), NULL, NULL, 'DETAILED')
-- record size: 25
By default, you have snapshot isolation OFF, If you turn it ON, SQL will maintain snapshots of data for running transactions.
Example: On connection 1, you are running big select. On connection 2, you update some of the records that are going to be returned by first select.
In snapshot isolation ON, SQL will make a temporary copy of the data, affected by update, so SELECT will return original data.
Any additional data manipulation will affect performance. That's why this setting is OFF by default.