0

I have a table Table1 that is updated in small chunks using below query:

update top (1000) Table1
    set VarcharColumn1 = 'SomeValue'
from Table1
where ID in (select ID from Table2)
      and VarcharColumn1 is NULL

Additional details:

Table2 has 90000 rows, and total number of rows that need to be updated in Table1, is also 90000 (1 to 1 relationship)

Also when Table1 rows are updated, there is a trigger on Table1 that inserts rows as they were before update, to table Table1History
So this means when I update 1000 rows in Table1, 1000 rows inserted into Table1History

Question:

When I update top 100 rows, no Table Lock Escalation happens

I monitor this using Extended Events "lock_escalation" event, and also in Performance Monitor - SQLServer:Access Methods - Table Lock Escalations / sec

When I update top 1000 or 500 rows, Table Lock Escalation IS happening on Table1

So I wonder, what is the mechanism or formula that is used by SQL Server     
to escalate locking to table level ?  

In google it says 5000 rows is the threshold, but obviously in my case 1000 or 500 rows is enough to cause Table Lock Escalation on Table1

extended events lock_escalation

  • Could you add the details of the event that reports the lock escalation to the question? Thanks! – Randi Vertongen Aug 14 at 10:10
  • 1
    Just to check, you could trace all lock acquisitions as I do here. – Michael Green Aug 14 at 11:12
  • @RandiVertongen added picture – aleksey vitsko Aug 14 at 11:16
2

Lock escalation is not exactly based on 5k rows, but rather a number of locks pr. level in the locking hierarchy. Once you hit the threshold, locks escalate to the next object level, until you eventually reach table-level which usually has a negative impact on the application. To work around this the easiest, consider how many rows you are affecting in the DELETE TOP() and how many pages that correlates to. The amount of rows in a page is defined by with width of the row. If you have many columns (requiring lots of byte-storage), your row-width is bigger, then a table with fewer columns. A page can contain roughly 8k-bytes of data.

"Books Online states that the threshold for a lock escalation is reached when the statement has acquired in excess of 5,000 row or page level locks on a single instance of an object. Also some blogs (which I came across in the Internet) just take 5000 value as a threshold point and not consider other parameters. When rows exceed 5000 an attempt is made to convert a higher-level lock on the object (either an IS or an IX lock) to an S lock or an X lock on the table. If this fails, perhaps because the table is being used by someone else, then SQL Server will back off and try again if it acquires another 1,250 locks on the same instance of the object. Remember that all locks attained must originate from the same object within the statement to qualify for exceeding the lock threshold, so 4,000 locks from tableA that is self-joined (i.e., another set of 4,000 locks) would not qualify." [taken from book "Professional SQL Server 2008 Internals and Troubleshooting" by Christian Bolton et al. published by Wrox ]

Good info in the page-object in SQL Server: https://www.sqlskills.com/blogs/paul/inside-the-storage-engine-anatomy-of-a-page/

There is an option to disable lock escalation as part of your table-definition. Buts it not advisable in most cases. I'd advise to not go this route until you've tried designing with lock escalation in mind. See more here: What is disadvantage of disabling lock escalation in SQL Server 2016

  • so in my case, when table lock escalation is happening even if I update just top (1000) rows, this possibly means that my rows are pretty wide and can take several pages per row, and that is why actual number of page locks can exceed 5000 ? – aleksey vitsko Aug 15 at 10:31
  • Could you provide the table defintion? Im pretty sure you are doing locks on the nested select, so maybe thats your source of trouble. – Kasper Brandenburg Aug 18 at 5:57
1

Note (select ID from Table2) could return (theorically) 90k rows. Maybe the plan could change with a "exists" or a join between table1 and table2.

Anyway a possible workaourd could be a cursor-loop to avoid large number of rows locked on each iteration.

  • thanks, that is what I did - use loop to update top 100 at a time, many times with small delay until there is no rows left – aleksey vitsko Aug 15 at 10:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.