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)
Related
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
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
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.
I have two tables. Tables 2 contains more recent records.
Table 1 has 900K records and Table 2 about the same.
To execute the query below takes about 10 mins. Most of the queries (at the time of execution the query below) to table 1 give timeout exception.
DELETE T1
FROM Table1 T1 WITH(NOLOCK)
LEFT OUTER JOIN Table2 T2
ON T1.ID = T2.ID
WHERE T2.ID IS NULL AND T1.ID IS NOT NULL
Could someone help me to optimize the query above or write something more efficient?
Also how to fix the problem with time out issue?
Optimizer will likely chose to block whole table as it is easier to do if it needs to delete that many rows. In the case like this I delete in chunks.
while(1 = 1)
begin
with cte
as
(
select *
from Table1
where Id not in (select Id from Table2)
)
delete top(1000) cte
if ##rowcount = 0
break
waitfor delay '00:00:01' -- give it some rest :)
end
So the query deletes 1000 rows at a time. Optimizer will likely lock just a page to delete the rows, not whole table.
The total time of this query execution will be longer, but it will not block other callers.
Disclaimer: assumed MS SQL.
Another approach is to use SNAPSHOT transaction. This way table readers will not be blocked while rows are being deleted.
Wait a second, are you trying to do this...
DELETE Table1 WHERE ID NOT IN (SELECT ID FROM Table2)
?
If so, that's how I would write it.
You could also try to update the statistics on both tables. And of course indexes on Table1.ID and Table2.ID could speed things up considerably.
EDIT: If you're getting timeouts from the designer, increase the "Designer" timeout value in SSMS (default is 30 seconds). Tools -> Options -> Designers -> "Override connection string time-out value for table designer updates" -> enter reasonable number (in seconds).
Both ID columns need an index
Then use simpler SQL
DELETE Table1 WHERE NOT EXISTS (SELECT * FROM Table2 WHERE Table1.ID = Table2.ID)
I am connecting two databases for data migration. I want to check whether a record from the table of the first database exists in the second database.
I.e. from the source database user table I want to migrate data to destination database user table.
How to write query using if not exists?
insert into myTable
select * from myOldTable ot
where NOT EXISTS (select 1 from mytable t where t.ID = ot.ID)
You might be better writing it as a join
insert into myTable
select ot.*
from myOldTable ot
LEFT JOIN mtTable t
ON ot.ID = t.ID
WHERE t.ID IS NULL
or depending on your database, a merge might be better, there are lots of options
I find the following syntax easiest to read:
insert TargetTable
(col1, col2)
from SourceTable as source
where not exists
(
select *
from TargetTable as duplicate
where source.col1 = duplicate.col1
and source.col2 = duplicate.col2
)
Normally you don't have to worry about concurrency during a data migration. If you do, you can specify locking hints like with (tablock) or a higher transaction isolation level. Or you can use merge as suggested, but that has a rather convoluted syntax.
SQL2003 defines MERGE, otherwise you can do an an INSERT INTO ... SELECT and in the SELECT you should LEFT JOIN in the destination table using the natural key in the ON predicate and then just chuck in a WHERE <column> IS NULL.
select * from db1.schema1.table1
intersect
select * from db2.schema2.table2