What Is The Purpose of Rowlock on Delete and When Should I Use It

What is the purpose of ROWLOCK on Delete and when should I use it?

The with (rowlock) is a hint that instructs the database that it should keep locks on a row scope. That means that the database will avoid escalating locks to block or table scope.

You use the hint when only a single or only a few rows will be affected by the query, to keep the lock from locking rows that will not be deleted by the query. That will let another query read unrelated rows at the same time instead of having to wait for the delete to complete.

If you use it on a query that will delete a lot of rows, it may degrade the performance as the database will try to avoid escalating the locks to a larger scope, even if it would have been more efficient.

Normally you shouldn't need to add such hints to a query, because the database knows what kind of lock to use. It's only in situations where you get performance problems because the database made the wrong decision, that you should add such hints to a query.

Is it possible to set the ROWLOCK table hint from a transaction isolation level in MSSQL?

If I understand your question clearly, it looks like you are looking for SNAPSHOT ISOLATION. It does not do row locks but use row versioning. As per your question, it looks like you do not want any locks on "Read" because of performance but wants to maintain the integrity for write operations.

The snapshot isolation level uses row versioning to provide transaction-level read consistency. Read operations acquire no page or row locks but does row versioning with DML statements.

As with (rowlock) is a hint that instructs the database that it should keep locks on a row scope. That means that the database will avoid escalating locks to block or table scope. That will let another query read unrelated rows at the same time instead of having to wait for the delete to complete.

The above mentioned use of rowlock can be achieved using SNAPSHOT ISOLATION where you will be able to read unrelated rows.

Deletion of rows in table cause LOCKS

I have seen similar sporadic problems in the past where even in small batches 0f 5000 records, locking would still happen. In our case, each delete/update was contained in its own Begin Tran...Commit loop. To correct the problem, the logic of

WaitFor DELAY '00:00:00:01'

was placed at the top of each loop through and that corrected the problem.

Delete statements locks table

One possibility is that you need to index the column by which you are searching the table for rows to delete. If you do not have an index, then SQL Server will acquire many more locks while it searches for the rows to delete.

I highly recommend deleting small chunks of rows in a loop. As others have pointed out, if you try to delete more than about 5,000 rows at once, SQL Server will escalate the row locks into a table lock. Deleting fewer records at a time-- say, 1,000-- avoids locking the entire table. Your job can continue looping over the deletes until it is done.

The pseudocode for a looped delete looks like this:

declare @MoreRowsToDelete bit
set @MoreRowsToDelete = 1
while @MoreRowsToDelete = 1
begin
delete top (1000) MyTable from MyTable where MyColumn = SomeCriteria
if not exists (select top 1 * from MyTable where MyColumn = SomeCriteria)
set @MoreRowsToDelete = 0
end

Alternatively, you could look at the @@ROWCOUNT and use READPAST hint to avoid locked rows:

declare @RowCount int
set @RowCount = 1 -- priming the loop
while @RowCount > 0
begin
delete top (1000) MyTable from MyTable with (readpast) where MyColumn = SomeCriteria
set @RowCount = @@ROWCOUNT
end

Note that the lock escalation threshold depends on other factors like concurrent activity. If you regularly have so much activity that even a 1,000 deletion will escalate to a table lock, you can lower the number of rows deleted at once.

See the Microsoft documentation on lock escalation for more information.

update with rowlock in MSSQL server

Lock hints are only hints. You can't "force" SQL to take a particular kind of lock.

You can see the locks being taken with the following query:

select      tl.request_session_id,
tl.resource_type,
tl.request_mode,
tl.resource_description,
tl.request_status
from sys.dm_tran_locks tl
join sys.partitions pt on pt.hobt_id = tl.resource_associated_entity_id
join sys.objects ob on ob.object_id = pt.object_id
where tl.resource_database_id = db_id()
order by tl.request_session_id

OK, let's run some code in an SSMS query window:

create table t(i int, j int);
insert t values (1, 1), (2, 2);

begin tran;
update t with(rowlock) set j = 2 where i = 1;

Open a second SSMS window, and run this:

begin tran;
update t with(rowlock) set j = 2 where i = 2;

The second execution will be blocked. Why?

Run the locking query in a third window, and note that there are two rows with a resource_type of RID, one with a status of "grant", the other with a status of "wait". We'll get to the RID bit in a second. Also, look at the resource_description column for those rows. It's the same value.

OK, so what's a resource_description? It depends on theresource_type. But for our RID it represents: the file id, then the page id, then the row id (also known as the slot). But why are both executions taking a lock on row slot 0? Shouldn't they be trying to lock different rows? After all, we are updating different rows.

David Browne has given the answer: In order to find the correct row to update, SQL has to scan the entire table, because there is no index telling it how many rows there are where i = 1. It will take an update lock on each row as it scans through. Why does it take an update lock on each row? Well, it's not to "do" the update, to so speak. It will take an exclusive lock for that. Update locks are pretty much always taken to prevent deadlocks.

So, the first query has scanned through the rows, taking a U lock on each row. Of course, it found the row it wanted to update right away, in slot 0, and took an X lock. And it still has that X lock, because we haven't committed.

Then we started the second query, which also has to scan all of the rows to find the one it wants. It started off by trying to take the U lock on the first row, and was blocked. The X lock of our first query is blocking it.

So, you see, even with row locking, your second query is still blocked.

OK, let's rollback the queries, and see what happens if we have the first query update the second row, and the second query update the first row? Does that work? Nope! Because SQL still has no way of knowing how many rows match the predicate. So the first query takes its update lock on slot 0, sees that it doesn't have to update it, takes its update lock on slot 1, sees the correct value for i, takes its exclusive lock, and waits for us to commit.

The query 2 comes along, takes the update lock on slot 0, sees the value it wants, takes its exclusive lock, updates the value, and then tries to take an update lock on slot 1, because that might also have the value it wants.

You'll also see "intent locks" on the next "level" up, i.e., the page. The operation is letting the rest of the engine know that it might want to escalate the lock to the page level at some point in the future. But that's not a factor here. Page locking is not causing the issue.

Solution in this case? Add an index on column i. In this case, that's probably the primary key. You can then do the updates in either order. Asking for row locking in this case makes no difference, because SQL doesn't know how many rows match the predicate. But even if you try to force a row lock in some situation, and even with a primary key or appropriate index, SQL can still choose to escalate the lock type, because it can be way more efficient to lock a whole page, or a whole table, than to lock and unlock individual rows.

sql rowlock on select statement

You can't lock a row like that using DB engine locks.

Most other strategies would rely on keeping the connection open (such as sp_getapplock) and this is nonsensical in web apps.

Even if you set a flag on the row, what happens if the user simply closes the browser mid-edit?

I'd suggest using a timestamp/rowversion column to detect changes to the row in other sessions.



Related Topics



Leave a reply



Submit