This is a quick post to clarify an article I saw on SQLServerCentral this morning that seemed to state that transaction rollbacks push data into database snapshots. This is absolutely not true.
A database page is copied into a database snapshot before it is changed in the source database. Although the mechanism is commonly called copy-on-write, it's more technically accurate to call it copy-before-write (but this makes it a bit harder to understand for many people). Once a page has been copied into the database snapshot, it is never removed from the database snapshot, and won't ever be copied into it again, as the database snapshot already has the correct point-in-time copy of the updated page. (For more info on database snapshots in general, see the Books Online entry Database Snapshots.)
A transaction makes one or more changes to the database, updating one or more pages. These pages will be copied into the database snapshot if they're not already there, so the pre-change image (that existed at the time the database snapshot was created) is preserved.
If the transaction rolls back, the rollback occurs by generating the reverse operations that the transaction performed and applying them to the database (e.g. an insert will be rolled back by the generation and application of a delete; an update will be rolled back by replacing the updated parts of the record with the pre-update values). I'll explain more about this in a future blog post.
These rollback operations will occur on the same pages that the initial transaction operations occured on. This means that no other pages will be changed by the rollback operations and so no further pages will be copied into the database snapshot by a rollback. Pages can't be removed from the database snapshot when the transaction rolls back because they have still changed in the source database (although the net effect of the transaction+rollback is no logical changes to the data, the page headers will have changed to have an updated Log Sequence Number on), and so the copy in the database snapshot is still required to preserve the point-in-time view of the database (at the physical level) as of the time the database snapshot was created.
I'll prove this to you with a simple script that you can play around with to convince yourself also.
USE master;
GODROP DATABASE SnapRollbackTest_Snapshot;
GO
DROP DATABASE SnapRollbackTest;
GOCREATE DATABASE SnapRollbackTest;
GO
USE SnapRollbackTest;
GOCREATE TABLE MyTable (c1 INT);
CREATE CLUSTERED INDEX MyTable_CL ON MyTable (c1);
GOSET NOCOUNT ON;
GODECLARE @a INT;
SELECT @a = 1;
WHILE (@a < 100001)
BEGIN
INSERT INTO MyTable (c1) VALUES (@a);
SELECT @a = @a + 1;
END;
GOCREATE DATABASE SnapRollbackTest_Snapshot ON
(NAME = N'SnapRollbackTest', FILENAME = N'C:\SQLskills\test\SnapRollbackTest.mdfss')
AS SNAPSHOT OF SnapRollbackTest;
GO— Initial size
SELECT size_on_disk_bytes AS [Initial Size (bytes)] FROM sys.dm_io_virtual_file_stats (DB_ID ('SnapRollbackTest_Snapshot'), 1);
GO— Start transaction
BEGIN TRAN
GO
UPDATE MyTable SET c1 = 42;
GO
CHECKPOINT; — to make sure absolutely everything is flushed to disk
GOSELECT size_on_disk_bytes AS [After Transaction (bytes)] FROM sys.dm_io_virtual_file_stats (DB_ID ('SnapRollbackTest_Snapshot'), 1);
GO— Rollback
ROLLBACK TRAN;
GOSELECT size_on_disk_bytes AS [After Rollback (bytes)] FROM sys.dm_io_virtual_file_stats (DB_ID ('SnapRollbackTest_Snapshot'), 1);
GO
Initial Size (bytes)
——————–
196608After Transaction (bytes)
————————-
1835008After Rollback (bytes)
———————-
1835008
You can clearly see that the size of the database snapshot did NOT increase at all because of the transaction rollback. Using the script above you can try this using a heap, clustered index, various combinations of row size and number of rows – the result will be the same – the database snapshot will not increase in size because of a transaction rollback. I tried a bunch of different combinations, all with the same result.
In the back of my head there's a niggly feeling that there's a funky, rare, pathalogical case where some weird combination of operations results in a page split when rolled-back, but I can't engineer it.
Bottom line – transaction rollbacks do not cause the database snapshot to increase in size, as the rollback operates on the database pages that have already been copied into the snapshot because they changed due to the operations of the transaction itself.
Hope this helps!
PS As one of the commenters pointed out, the initial snapshot size can be affected by the crash-recovery that is run when the snapshot is created. I go into details on that process in this post as it can be confusing when CHECKDB runs.
8 thoughts on “Misconceptions around database snapshots and transaction rollbacks”
If you have it, you can run SQL Server Developer Edition on your laptop. It’s basically the full Enterprise Edition.
Paul,
Nice post, but I don’t think this is clear here. The rollback doesn’t affect the snapshot size, but if I read correctly, the transaction will affect the size, even if it’s rolled back.
So if I have a 1GB database and a 1kb snapshot (empty). If I start a transaction that changes 100MB of data in my data file, my snapshot will grow to roughly 100MB. If I then rollback the transaction, the snapshot will remain at 100MB, not drop back down to 1kb.
Is that correct?
Nice demo script Paul, the true and original In Recovery!
Great post. Thanks for sharing. Unfortunately I cannot run the script on my laptop as SQL Server 2005 Express Edition does not support snapshots.
You could try Enterprise Evalution Edition…
@Steve Yup – that’s exactly right – I explain that just before the script. The original article that I’m debunking says the *rollback* copies pages into the snapshot – that’s not the case – it’s the actual transaction itself.
(love the blog…long time reader, first time poster)
One case when transaction rollback will affect the snapshot size is for transactions that are active when the snapshot is created. Those transactions get rolled back (in the snapshot) and the pages modified during undo are copied into the snapshot files. This is probably not the case described in the original article, but I thought I’d mention it for the sake of completeness.
Hi Lewis – absolutely. I go into some depth on that topic in https://www.sqlskills.com/blogs/paul/post/Do-transactions-rollback-when-DBCC-CHECKDB-runs.aspx – I’ll add the link the post. Cheers