SQL Server: how to set default isolation level for the entire stored procedure? - sql

If right after BEGIN I have SET TRANSACTION ISOLATION LEVEL ... statement, will the given transaction level in force for the entire scope of the stored procedure regardless if I use BEGIN TRANSACTION or not? Namely if I have simple SELECT statements, which are atomic/transacted by definition, will the default transaction level for them set to the given one?
BEGIN
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
-- will a transaction level for a atomic transaction created by SQL Server for this statement be READ COMMITTED
SELECT * FROM T
END

First, the default isolation level in SQL Server is Read Committed, so that statement doesn't really do anything unless you've changed the default isolation level.
But, in general, yes, SET Transaction Isolation Level will change the isolation level for the whole procedure (the duration of the connection, in fact)
Keep in mind that all SQL statements are implicit transactions meaning that if, for example, an update fails 99% through, it will rollback automatically; no BEGIN TRAN/COMMIT is necessary.
To answer your question, yes, your SELECT statements will inherit the isolation level you set (or the default if you do not set one) unless you override the behavior with a query hint like WITH NOLOCK which will make the individual query behave as though you did SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

Related

How to create transaction with isolation level in SQL

How to create a transaction with isolation level in SQL.
I'v tried something like this, but obviously it does not work:
INSERT INTO test(col1) VALUES ('test')
SET TRANSACTION ISOLATION LEVEL read stability;
COMMIT WORK;
I'm using SQL DB2 LUW
https://www.ibm.com/docs/en/db2/11.5?topic=information-sqlj-set-transaction-clause says:
You can execute SET TRANSACTION only at the beginning of a transaction.
https://www.ibm.com/docs/en/i/7.5?topic=statements-set-transaction says:
The SET TRANSACTION statement can only be executed when it is the
first SQL statement in a unit of work, unless:
all previous statements executed in the unit of work are SET
TRANSACTION statements or statements that are executed under isolation
level NC, or
it is executed in a trigger.
I'm not a user of DB2, but this seems to say that you must SET TRANSACTION before your INSERT. This matches my experience in other RDBMS products.
Look at the SET CURRENT ISOLATION statement.

Isolation levels and select for update

What is the relation between isolation levels of relational databases and select for update?
If I use the plain vanilla JDBC connectivity with SQL Server and set isolation level to READ_REPEATABLE and use a simple select, would I see inconsistency in repeatable reads or not? Or should I use select for update always to avoid inconsistent repeatable reads in transactions? If so, what is the deal with isolation levels, how they would come into play?
SQL Server doesn't have the select ... for update syntax. The equivalent in SQL Server is to use the UPDLOCK table hint.
This hint is used when reading a row and immediately updating the same row in an atomic transaction. EG
declare #balance = (select balance from account where accountId = #id)
update account set balance = #balance + #amount where accountId = #id
At READ COMMITTED, or in any isolation level without a mult-statement transaction, multiple sessions can run the first query, and have lost updates when updating the balance.
Using the REPEATABLE READ or SERIALIZABLE isolation level will prevent this update anomaly, but they do it by blocking the first writer if there are any concurrent transactions that have read the row, and if one of the other transactions attempts to update the row, causing a deadlock.
Mostly this behavior is not worth the performance cost and annoyance of handling deadlocks. So you use 'select for update' aka UPDLOCK to place a U lock on the row while reading and block subsequent readers from acquiring a conflicting lock.
eg
declare #balance = (select balance from account with (updlock) where accountId = #id)
update account set balance = #balance + #amount where accountId = #id
Not exactly sure what you mean by "inconsistent repeatable reads" but with the REPEATABLE READ isolation level in SQL Server, shared locks will be held until the end of the transaction. Only committed data will be returned and other sessions cannot modify the rows read until the transaction is committed (or auto-committed in the case of no explict transaction).
REPEATABLE READ does not prevent other sessions from inserting new rows so rerunning the same query in the same transaction may return new rows (phantom reads) that were not returned originally.
The documentation describes this in more detail along with the other transaction isolation levels.
There is no need to intervene with the default behavior using hints or otherwise.
SQL Server guarantees transaction isolation levels per your declared required level.
REPEATABLE READ guarantees that within a transaction, your statements will see a consistent view of the data that was read, but doesn't guarantee there will be no phantom rows. To avoid the latter you will need to use SERIALIZABLE.
The higher the isolation, the higher the concurrency penalty of course.
See the JDBC Page for isolation levels and the general page for SET TRANSACTION ISOLATION LEVEL for a somewhat more in-depth discussion.
HTH

Transaction Isolations level in SQL Server

I am trying to update table, which controlls application (application performs some select statements). I would like to update the table in transaction with isolation level set to read uncommited, so if application doesn't work as expected I can rollback transactions.
But following code doesn't work:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
go
begin transaction
go
update [DB].[dbo].[Table]
set ID = ID - 281
where ID > 2
When I open another query window, I cannot query this table... I thought, that with such transaction level I would be able to query the table without rolling back/commiting transaction.
Isolation level works in another way as you suppose.
You can only read uncommitted data, but others still cannot see what you done within transaction until you commit.
If you want to see uncommitted data from this transaction in your select you need to set
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
to this select
You need to use SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED from a session which reads data.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT *
FROM [DB].[dbo].[Table]
This query will execute immediately without lock. And you'll see the dirty data.

Proper way to restore database transaction level from read uncommitted

I have to get data from a table which is excessively updated. Dirty read is not a problem for me. I decided to use read uncommitted in my stored procedure.
Then I added this line before select:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
I learned that this code scope is connection, unlike nolock. I heard you should change it to default after your work is done is that right?
Do I have to just add
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
end of the line? I could not find any example on the web where isolation level is changed back after work is done. Is there any example?
Only one of the isolation level options can be set at a time, and it remains set for that connection until it is explicitly changed. All read operations performed within the transaction operate under the rules for the specified isolation level unless a table hint in the FROM clause of a statement specifies different locking or versioning behavior for a table.
...
If you issue SET TRANSACTION ISOLATION LEVEL in a stored procedure or trigger, when the object returns control the isolation level is reset to the level in effect when the object was invoked. For example, if you set REPEATABLE READ in a batch, and the batch then calls a stored procedure that sets the isolation level to SERIALIZABLE, the isolation level setting reverts to REPEATABLE READ when the stored procedure returns control to the batch.
https://msdn.microsoft.com/en-us/library/ms173763.aspx

Transaction isolation for sql statements

Can we set isolation level for plain SQL statements in a stored procedure in SQL Server 2005/2008?
Case 1: (This will work fine)
CREATE PROCEDURE MySP
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRAN
SELECT * FROM MyTable
COMMIT TRAN
END
Case 2: (does this isolation stuff work here?)
CREATE PROCEDURE MySP
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM MyTable
END
If case 2 is correct, would it work for several select statements as well?
Yes it will work for multiple select statements.
If you are worried about the lack if a transaction in the second stored procedure you should know that the query is executed under an implicit transaction as opposed to an explicit transaction that you have in the first stored procedure.
If you use SET TRANSACTION ISOLATION LEVEL in a stored procedure, this transaction isolation level is used for the duration of the stored proc. According to MSDN:
If you issue SET TRANSACTION ISOLATION LEVEL in a stored procedure or trigger, when the object returns control the isolation level is reset to the level in effect when the object was invoked.
Setting transaction isolation level is not the same as starting a transaction. Transaction isolation level tells SQL Server how to control locking.
If you only have multiple SELECT queries with READ UNCOMMITTED transaction isolation level, putting them all into a transaction won't make practical difference.
Isolation level can be set either at the session level with a session option or at the query level with a table hint. To set isolation level of the whole session we use command:
SET TRANSACTION ISOLATION LEVEL <isolation name>;
You can use a table hint to set the isolation level of a query as:
SELECT ... FROM <table> WITH (<isolationname>);
so in your case it would be like:
SELECT *
FROM MyTable WITH (READCOMMITTEDLOCK);
One thing here to note is: with the session option a space is specified between the words in case the name of the isolation level is made of more than one word, such as REPEATABLE READ. With the query hint,we don’t specify a space between the words—for example, WITH (REPEATABLEREAD).