Goal:
Delete several billion records old records (roughly 600GB) across three tables with zero downtime.
Methodology and Background:
I plan to delete batches of records associated with 1 Million MyIDs at a time (ie MyID BETWEEN 1 AND 1000000). While the delete is running, two of the tables will be very hot but activity on the third table can be safely suspended. In the two hot tables, MyID is the clustering key. In the third, cold, table I have a non-clustered index on MyID.
Besides the DELETE operation, the other activity in the hot tables will consist of INSERT, probably several per second. MyID is an IDENTITY and the newly inserted records will not be in range of any of the DELETE batches.
If it helps understand potential performance, SELECT of an aggregate of a sample batch of these rows takes < 1 second on the tables clustered by MyID and about 2 seconds on the non-clustered table. I do not have a prod replica for this particular database to play in so I cannot say how long the deletes will take, however once I deploy this to DEV I'll have a better idea.
Side note: To address log size, I am wrapping these batches in transactions and upping the TLog backup frequency from 15 to 5 minutes. I have 150GB of available log space.
The Question
I read in the MS docs:
By default, a DELETE statement always acquires an exclusive (X) lock on the table it modifies, and holds that lock until the transaction completes.
I am very wary of using locking hints, but in this case can I safely use one to avoid TABLOCKX? Are there other ways besides a locking hint to avoid TABLOCKX?
Best Answer
In this case it's may be more convenient to copy the rows that should remain rather than delete. Note that all 600Gb will move to your log file surely.
This is wrong. SQL Server never starts with
table lock
unless the corresponding hint was specified.In your case whith filtering on
PK
ranges:MyID BETWEEN 1 AND 1000000
it most probably will start withpage
locks. And here all depends on how many records fit in onepage
. If locking of1000000
records withpage
granularity takes less than5000
locks you'll be fine withpage
locks, if you'll have morelocks
per statementlock escalation
will happen and your table will be completely locked.SQL Server Concurrency: Locking, Blocking and Row Versioning by K.Delaney
So only by testing and monitoring locks acquired you can find the optimal
batch size
and avoidlock escalation
. You can approximately calculate yourbatch size
if you know the average of rows per page in your table. Or you can force page locking by usingPAGLOCK
and even disable lock escalation on your table: