I write multiple SELECT statements in one window and normally highlight and run them as needed.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM Table1
SELECT * FROM Table2
SELECT * FROM Table3
This is an example of what my window might look like, now from here I will only highlight SELECT * FROM Table2 and run it.
Will SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; still apply even if it is not highlighted with the statement?
If it does still apply, how does it do it?
Ignoring the usual spiel about why you shouldn't be using READ UNCOMMITTED...
Setting the TRANSACTION ISOLATION LEVEL applies at the connection level, until the connection is dropped or another level is set.
From BOL:
SET TRANSACTION ISOLATION LEVEL (Transact-SQL)
Controls the locking and row versioning behavior of Transact-SQL statements issued by a connection to SQL Server.
So running this once in your SSMS query window will apply for all batched queries you send to the server within that connection (window).
Alternatively, you could add WITH (NOLOCK) to your statements to apply to individual ones, e.g.
SELECT * FROM Table1;
SELECT * FROM Table2 WITH (NOLOCK);
SELECT * FROM Table3;
No, if you didn't execute it, it will not apply to your connection. As Chris mentioned in the previous answer, once you execute it in your connection (query windows in SSMS), all following queries in this connection will be executed using this transaction isolation level.
If you have doubts, you can check which transaction isolation level used for your connection right now:
DBCC USEROPTIONS
Related
Does this query below work or do I have use explicitly transaction being and end?
Yes I know the dangers of the read uncommitted
SET TRANSACTION isolation level READ uncommitted
SELECT TOP 100 tblguilds.guild_id,
tblguilds.guildname,
tblguilds.leaderuserid,
tblusersprofile.username
FROM tblguilds
LEFT JOIN tblusersprofile
ON tblusersprofile.userid = tblguilds.leaderuserid
WHERE tblguilds.guild_id NOT IN (SELECT guildcode
FROM tblguildapplied
WHERE userid = 1)
ORDER BY Newid()
Yes that will work but be aware that it will be in effect for the entire session. Meaning any SQL that you execute after that select will be using that isolation level. If you want to restrict that to certain tables in the select stmt then consider using the NOLOCK hint
See more over here :
WITH (NOLOCK) vs SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
The Begin transaction and commit ( there is no END transaction) applies only to insert/updates/deletes
On a side note I would modify that query to use a left outer join instead of a NOT IN to improve performance.
In MS SQL Server, if I use "SET TRANSACTION ISOLATION LEVEL" in a stored procedure, do I need to wrap the select statements in a BEGIN/END TRANSACTION Block? Will the following work as expected?
CREATE PROCEDURE my_sproc AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM MyTable
END
The TRANSACTION ISOLATION LEVEL setting is a connection-level setting. There's no need to wrap it in a transaction.
That being said, you understand you will have dirty reads and such from this setting?
You can accomplish the same thing on a query-by-query basis by using locking hints such as:
SELECT * FROM MyTable WITH (NOLOCK)
SET TRANSACTION ISOLATION LEVEL is different to BEGIN/COMMIT/ROLLBACK
The first changes the isolation vs concurrency settings
The second defines the atomic "unit of work"
There is no direct link or interaction: different concepts
I tried to reproduce the situation of question [1].
On table, taken and filled with data from wiki's "Isolation (database systems)" [2],
in SQL Server 2008 R2 SSMS, I executed:
1) first in first tab (window) of SSMS
-- transaction isolation level in first window does not influence results (?)
-- initially I thought that second transaction in 2) runs at the level set in first window
begin transaction
INSERT INTO users VALUES ( 3, 'Bob', 27 )
waitfor delay '00:00:22'
rollback
2) immediately after, in second window
-- this is what I commented/uncommented
-- set transaction isolation level SERIALIZABLE
-- set transaction isolation level READ REPEATABLE
-- set transaction isolation level READ COMMITTED
-- set transaction isolation level READ UNCOMMITTED
SELECT * FROM users --WITH(NOLOCK)
Update:
Sorry, results were corrected.
My results, depending on isolation level set in 2), are that SELECT returns:
immediately (reading uncommitted inserted row)
for all cases of SELECT with NOLOCK
for READ UNCOMMITTED (SELECT either with or without NOLOCK)
is waiting the completion of transaction 1) (ONLY IF SELECT is without NOLOCK) and
in READ COMMITTED and higher (REPEATABLE READ, SERIALIZABLE) transaction isolation level
These results contradict to situation described in question (and explained in answers?) [1]
(for example, that SELECT with NOCHECK is waiting completion of 1)), etc.
How can my results and [1] be explained?
Update2:
This question is really subquestion of my questions [3] (or the result of them not being answered).
Cited:
[1]
Explain locking behavior in SQL Server
Explain locking behavior in SQL Server
[2]
"Isolation (database systems)"
Plz add trailing ) to link. I cannot manage to preserve it here in the link!
http://en.wikipedia.org/wiki/Isolation_(database_systems)
[3]
Is NOLOCK the default for SELECT statements in SQL Server 2005?
Is NOLOCK the default for SELECT statements in SQL Server 2005?
There is a useful MSDN link her talk about locking hints in SQL 2008. Maybe in your example its a case of SQL Server 2008 disfavoring your tables locks?
(The following snippet from the link below talks about locks potentially being ingored by SQL Server 2008)
As shown in the following example, if the transaction isolation level is set to SERIALIZABLE, and the table-level locking hint NOLOCK is used with the SELECT statement, key-range locks typically used to maintain serializable transactions are not taken.
CopyUSE AdventureWorks2008R2;
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
GO
BEGIN TRANSACTION;
GO
SELECT Title
FROM HumanResources.Employee WITH (NOLOCK);
GO
-- Get information about the locks held by
-- the transaction.
SELECT
resource_type,
resource_subtype,
request_mode
FROM sys.dm_tran_locks
WHERE request_session_id = ##spid;
-- End the transaction.
ROLLBACK;
GO
The only lock taken that references HumanResources.Employee is a schema stability (Sch-S) lock. In this case, serializability is no longer guaranteed.
In SQL Server 2008, the LOCK_ESCALATION option of A LTER TABLE can disfavor table locks, and enable HoBT locks on partitioned tables. This option is not a locking hint, but can but used to reduce lock escalation. For more information, see ALTER TABLE (Transact-SQL).
The hint in the second query overrides transaction isolation level.
SELECT ... WITH (NOLOCK) is basically identical to SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT ....
With any other isolation level the locks are honored, so the second transaction waits until the locks are released by the first one.
When I perform a select/Insert query, does SQL Server automatically create an implicit transaction and thus treat it as one atomic operation?
Take the following query that inserts a value into a table if it isn't already there:
INSERT INTO Table1 (FieldA)
SELECT 'newvalue'
WHERE NOT EXISTS (Select * FROM Table1 where FieldA='newvalue')
Is there any possibility of 'newvalue' being inserted into the table by another user between the evaluation of the WHERE clause and the execution of the INSERT clause if I it isn't explicitly wrapped in a transaction?
You are confusing between transaction and locking. Transaction reverts your data back to the original state if there is any error. If not, it will move the data to the new state. You will never ever have your data in an intermittent state when the operations are transacted. On the other hand, locking is the one that allows or prevents multiple users from accessing the data simultaneously. To answer your question, select...insert is atomic and as long as no granular locks are explicitly requested, no other user will be able to insert while select..insert is in progress.
John, the answer to this depends on your current isolation level. If you're set to READ UNCOMMITTED you could be looking for trouble, but with a higher isolation level, you should not get additional records in the table between the select and insert. With a READ COMMITTED (the default), REPEATABLE READ, or SERIALIZABLE isolation level, you should be covered.
Using SSMS 2016, it can be verified that the Select/Insert statement requests a lock (and so most likely operates atomically):
Open a new query/connection for the following transaction and set a break-point on ROLLBACK TRANSACTION before starting the debugger:
BEGIN TRANSACTION
INSERT INTO Table1 (FieldA) VALUES ('newvalue');
ROLLBACK TRANSACTION --[break-point]
While at the above break-point, execute the following from a separate query window to show any locks (may take a few seconds to register any output):
SELECT * FROM sys.dm_tran_locks
WHERE resource_database_id = DB_ID()
AND resource_associated_entity_id = OBJECT_ID(N'dbo.Table1');
There should be a single lock associated to the BEGIN TRANSACTION/INSERT above (since by default runs in an ISOLATION LEVEL of READ COMMITTED)
OBJECT ** ********** * IX LOCK GRANT 1
From another instance of SSMS, open up a new query and run the following (while still stopped at the above break-point):
INSERT INTO Table1 (FieldA)
SELECT 'newvalue'
WHERE NOT EXISTS (Select * FROM Table1 where FieldA='newvalue')
This should hang with the string "(Executing)..." being displayed in the tab title of the query window (since ##LOCK_TIMEOUT is -1 by default).
Re-run the query from Step 2.
Another lock corresponding to the Select/Insert should now show:
OBJECT ** ********** 0 IX LOCK GRANT 1
OBJECT ** ********** 0 IX LOCK GRANT 1
ref: How to check which locks are held on a table
Is there a way to lock a SELECT in a Transaction? If a SELECT occurs, no more SELECTs are executed while the first one is not finished.
Thanks!
Not sure I understand your question correctly, but if you want to impose more rigorous locking than SQL Server's default, then you can either bump up the isolation level or use a locking hint. This can be useful if you first need to SELECT something and then later, based on the value SELECTed, do an UPDATE. To avoid a phantom UPDATE from another transaction (wherein the value you previously SELECTed was changed in b/w the SELECT and UPDATE), you can impose an update lock on your SELECT statement.
Eg:
select * from mytable with (holdlock, xlock)
Notice that the SELECT statement above uses the more rigorous update lock & holds that lock for the duration of the transaction. You would also want to wrap your statements in an explicit transaction, as in:
begin transaction
select * from mytable with (holdlock, xlock) -- exclusive lock held for the entire transaction
-- more code here...
update mytable set col='whatever' where ...
commit transaction
Be wary, of course, for long-running transactions.
Might want to look at Isolation Level instead of a hint
You'll need an isolation level of SERIALIZABLE:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
The other SELECT queries will block until the transaction completes in this case. The default level is usually READ COMMITTED.
it seems you're looking for a pessimistic locking strategy but without acctually locking your data. look into Application locks in sql server.
Changing your isolation levels is generally your best choice.
But, if for whatever reason that's not an option for you - you could also do an exclusive table lock...
select * from MyTable with (tablockx)
That would prevent any other selects on the table until your transaction is finished.