What is (are) difference between NOLOCK and UNCOMMITTED - sql

I use SQL Server 2012.
I write two queries but what is a different between NOLOCK and UnCommitted ?
SELECT lastname, firstname
FROM HR.Employees with (READUNCOMMITTED)
SELECT lastname, firstname
FROM HR.Employees with (NoLock)

NOLOCK : Is equivalent to READ UNCOMMITTED (source : MSDN)
NOLOCK or READ UNCOMMITTED Specifies that dirty reads are allowed. No shared locks are issued to prevent other transactions from modifying data read by the current transaction, and exclusive locks set by other transactions do not block the current transaction from reading the locked data. Allowing dirty reads can cause higher concurrency, but at the cost of reading data modifications that then are rolled back by other transactions
READ UNCOMMITTED and NOLOCK hints apply only to data locks. All queries, including those with READ UNCOMMITTED and NOLOCK hints, acquire Sch-S (schema stability) locks during compilation and execution. Because of this, queries are blocked when a concurrent transaction holds a Sch-M (schema modification) lock on the table

No difference in terms of their functions, like other have mentioned.
The single difference is that you can apply WITH(NOLOCK) selectively, on some tables but not others. READ UNCOMMITTED applies NOLOCK to all tables in a session.
If you do this:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT *
FROM Table1 T1
INNER JOIN Table2 T2 ON T1.ID = T2.id
It is functionally equivalent to:
SELECT *
FROM Table1 T1 WITH(NOLOCK)
INNER JOIN Table2 T2 WITH(NOLOCK) ON T1.ID = T2.ID
But you can also apply WITH(NOLOCK) selectively:
SELECT *
FROM Table1 T1 WITH(TABLOCK)
INNER JOIN Table2 WITH(NOLOCK) ON T1.ID = T2.ID

Under the hood they are the performing the same action.
The READ UNCOMMITTED isolation level is the least restrictive isolation level within SQL Server, which is also what makes it popular for developers when looking to reduce blocking.
The NOLOCK table hint behind the scenes performs the exact same action as running under the read-uncommitted isolation level.
The only difference between the two is that the READ UNCOMMITTED isolation level determines the locking mechanism for the entire connection and the NOLOCK table hint determines the locking mechanism for the table that you give the hint to.

There is no difference at the statement level.
You can set READUNCOMMITED at the session level and here you have to write
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

For NOLOCK , we need to put this hint on table level, so it is require to put for every tables level which are used in update transaction. So it is very lengthy and time consuming to put it everywhere tables refers in query. For READ UNCOMMITTED, We do not need to put it every tables level, just put at session level or query level and can be written at top of the query or stored procedure.
Let us look on small demo to elaborate it. First checking here database default isolation level
CREATE TABLE SAMPLETABLE
(
Col1 INT ,
Col2 VARCHAR(100)
)
INSERT INTO SAMPLETABLE(Col1,Col2)
SELECT 1,'Col1'
Union all
SELECT 2,'Col1'
BEGIN TRANSACTION
Update SAMPLETABLE Set Col2 = 'Value changed' Where col1 =1
Select * from SAMPLETABLE with (nolock)
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
Select * from SAMPLETABLE
Output is 1, Col1 for both query

Related

How does SQL Server add the with (nolock) one time and effect all query?

If I use N tables now, need to add N times with (nolock), for example
select * from T1 with (nolock)
join T2 with (nolock) ..
join T3 with (nolock) ..
join T4 with (nolock) ..
....
If I want to declare it once, what can I make the next all query work with (nolock)
like :
use all with (nolock)
select * from T1
join T2 ..
join T3 ..
join T4 ..
....
You can use set Transaction isolation level read uncommitted, e.g:
set Transaction isolation level read uncommitted
select * from T1
join T2 ..
join T3 ..
join T4 ..
Notice:
Transactions running at the READ UNCOMMITTED level do not issue shared locks to prevent other transactions from modifying data read by the current transaction. READ UNCOMMITTED transactions are also not blocked by exclusive locks that would prevent the current transaction from reading rows that have been modified but not committed by other transactions. When this option is set, it is possible to read uncommitted modifications, which are called dirty reads. Values in the data can be changed and rows can appear or disappear in the data set before the end of the transaction.
from SET TRANSACTION ISOLATION LEVEL (Transact-SQL) - SQL Server | Microsoft Docs

Using READ UNCOMMITTED with UNION ALL

I have a stored procedure that's in development, with multiple UNION ALL statements. This is historical data, and I've been instructed to use SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED. Setting aside the discussion over whether this is the right method, I'd like to know if I need to specify this ISOLATION LEVEL only once at the top of the stored procedure, or if I need to specify it after every UNION ALL, since they're different queries?
Example:
Alter procedure dbo.ExampleProcedure as
declare #StartDate datetime
declare #EndDate datetime
insert into myDB.DBO.InboundCalls
select I.Date, I.System, Count(*) as calls
from
(select Date, System, CallID from System1CallData C
Left Join someothertables as S on C.CallID = S.CallID
where (C.date >= #StartDate and C.date < #EndDate)) as I
Group by I.Date, I.System
Union ALL
select I.Date, I.System, Count(*) as calls
from
(select Date, System, CallID from System2CallData C
Left Join someothertables as S on C.CallID = S.CallID
where (C.date >= #StartDate and C.date < #EndDate)) as I
group by I.Date, I.System
Union ALL
select I.Date, I.System, Count(*) as calls
from
(select Date, System, CallID from System3CallData C
Left Join someothertables as S on C.CallID = S.CallID
where (C.date >= #StartDate and C.date < #EndDate)) as I
Group by I.Date, I.System
Order by I.Date asc, I.System asc, calls asc
So do I put SET TRANSACTION ISOLATION LEVEL after Alter Procedure dbo.ExampleProcedure as, or before the first SELECT, or before each nested SELECT? Thanks in advance for any guidance!
I'd like to know if I need to specify this ISOLATION LEVEL only once at the top of the stored procedure . . .
Only once at the top of the procedure, unless of course you're switching isolation levels within the procedure. The isolation level reverts to the previous level when the SP exits.
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.
Using the "read uncommitted" isolation level probably isn't risky on historical data. I'd presume the person instructing you to use that isolation level knows the risks and has determined that it's safe.
Historical data usually either doesn't change at all, or it changes at known intervals. (Say, quarterly. Or daily at 1:00 am.) I'd expect relatively few people to have insert privileges on those tables, and almost nobody to have update and delete privileges.
You might also test running three separate insert statements within a single transaction, rather than inserting the union of three select statements. The ORDER BY clause is probably a bad idea in production.

SQL Locking - Timeout issue

I have a SQL job which kind of process a queue of requests. It updates Table1. It is long process that takes like 15 minutes.
Meanwhile my application tries to read records from Table1 and displays them in a grid. The corresponding get proc has set tran isolation level read uncommited.
When the SQL job is running, my application always time outs while populating the grid. If the SQL job is not running it works fine.
My proc has appropriate isolation level, so I'm not getting why it still time out.
Thoughts?
Here is how my get proc looks like:
CREATE PROCEDURE dbo.MyGetProc(...)
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET NOCOUNT ON;
SELECT
...
FROM
(
SELECT
...
FROM
dbo.Table1
LEFT JOIN dbo.OtherTable1
WHERE ...
GROUP BY
...
) X
INNER JOIN dbo.OtherTable2
LEFT JOIN dbo.OtherTable3
LEFT JOIN dbo.OtherTable4
LEFT JOIN dbo.OtherTable5
LEFT JOIN dbo.OtherTable6
LEFT JOIN dbo.OtherTable6
ORDER BY
...
END
use
Select * from table1 with (nolock)
which reads commited data.

Update Query with Nolock hint

I am trying to put an with(NOLOCK) on an update query:
UPDATE pth_patchLookup with(nolock) SET ScanDateTime = Getdate() WHERE RegID = 312
but I get the following message :
NoLock hint is supported only with Select statement and not with update, insert and delete.
Is there any manner in which I can apply a 'NOLOCK" on this update query ?
Thanks for any help
(NOLOCK) disables shared locks and not exclusive locks.
you can use Read Committed isolation level in order to place an exclusive lock on select statements.
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
UPDATE pth_patchLookup SET ScanDateTime = Getdate() WHERE RegID = 312
And this?
UPDATE TOP (1000) v
SET idSupervisor = a.supervisor
FROM dbo.Venda_2014 v WITH ( NOLOCK )
INNER JOIN #supervidores_presentes a WITH (NOLOCK) ON v.IdVendedor = a.vendedor AND v.idEmpresaOriginal = a.empresa
WHERE IdDistribuidor IN ( 40 )
AND ISNULL(v.idSupervisor,0) = 0
AND datAnoMesRef >= '201501'
Go
Working fine for me.
NOLOCK is a select (only) hint and it's much a bad habit form older programmers since it was almost mandatory in SQL Server 7 but since SQL Server 2000 it's most unnecessary.
That hint in particular tell the engine the select can read rows even if it is in the middle of a uncommited transaction. Due to this you can experience dirty or ghost reads.
I strongly suggest you to read about isolation levels to know how to meet your particular system requirements.
Obs: Hints are not commands, you are only suggesting the engine to take a hint but the engine can decide to not use it.

SQL nolock and join

I am using a process that inserts data in 2 tables with rowlock, continuously. In the same time I want to use some queries on these tables. As I said the inserts are done with (rowlock) and I use for the queries the isolation level read uncomitted and nolock.
When I use the queries on a single table they work perfectly, but when I try to join the 2 tables I get this error:
Transaction (Process ID 88) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
Meanwhile, if I use the sp_lock procedure I found that the Key lock becomes a tab lock when I perform my queries.
Does anyone know if there is a special relation between (nolock) and join? And if there is how can I avoid it.
UPDATE:
Insert into tbl1 with (rowlock)
(
col1,
col2,
col3
)
select * from #tbl_temp
( this is in an infinite loop and the data from #tbl_temp is always changed. Actualy this is a more complex process but this is the idea.)
Insert into tbl2 with (rowlock)
(
col3,
col4,
col5
)
select * from #tbl_temp2
In the same time I perform
set transaction isolation level read uncomitted
select col1,col2,col3
from tbl1 with (nolock) -- works fine
select col1,col2,a.col3
from tbl1 with (nolock) join tbl2 with (nolock) on (tbl1.col3 = tbl2.col3)
-- deadlock
You might want to try turning on READ_COMMITTED_SHAPSHOT isolation level for your database.
(But be aware that this will put increased pressure on tempDB)