Skip to content

shannonlowder.com

Menu
  • About
  • Biml Interrogator Demo
  • Latest Posts
Menu

How Much Logging Goes on for a Clustered Index Drop?

Posted on December 19, 2011January 4, 2012 by slowder

A week back @fatherjack put out a question on #sqlhelp that immediately drew my curiousity. He wanted to know how much his log file would grow if he dropped his clustered index (primary key), and then created a new one. I was thinking that it wouldn’t write a lot of information to the log file, but I wasn’t 100% sure, so I did a little digging.

Water drop
I hit the MSDN. Looks like my initial thoughts were right…so long as there weren’t any non-clustered indexes pointing to that clustered index. I sent a reply to @fatherjack to see if he had any non-clustered indexes on that table. While I was waiting for his reply I decided to verify what I found in the MSDN.

First, I wanted to set my test database to FULL recovery mode, so it wouldn’t cycle the log entries until I said it was OK to do so.

USE [AdventureWorks]
GO
--set recovery to full
ALTER DATABASE adventureworks SET RECOVERY FULL;

Then I wanted a simple table with a Primary Key Clustered Index.

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[HumanResources].[Department_test]') AND type in (N'U'))
DROP TABLE [HumanResources].[Department_test]
GO

CREATE TABLE [HumanResources].[Department_test](
	[DepartmentID] [int] IDENTITY(1,1) NOT NULL,
	[Name] [dbo].[Name] NOT NULL,
	[GroupName] [dbo].[Name] NOT NULL,
	[ModifiedDate] [datetime] NOT NULL,
	CONSTRAINT [PK_DepartmentTest_DepartmentID] PRIMARY KEY CLUSTERED 
	(
		[DepartmentID] ASC
	)
) ON [PRIMARY]

GO

Next I wanted some data in that table, say 100,000 rows to start. Later I could crank this up to one million rows.

SET NOCOUNT ON
DECLARE @recordCount INT = 1

WHILE (@recordCount < 100001)
BEGIN
	INSERT INTO [HumanResources].[Department_test]
	(Name, GroupName, ModifiedDate)
	VALUES 
	('name' + CONVERT(VARCHAR(10), @recordcount), 'groupname' + CONVERT(VARCHAR(10), @recordcount), GETDATE())
	
	SET @recordCount = @recordCount + 1
END 	

--verify the count
SELECT COUNT(*) FROM [HumanResources].[Department_test]

Ok, I have my table and data. I also need a table I can store log entries to. One that will let me do a little analysis on what happened in the log file.

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'LogInfo') AND type in (N'U'))

DROP TABLE LogInfo
go
CREATE TABLE LogInfo 
	(currentLSN VARCHAR(50),
	Operation VARCHAR(50),
	Context VARCHAR(20),
	TransactionID VARCHAR(20),
	logblockGeneration INT)
GO

Ok, I have my test bed. Let's clear out the transaction log to make sure only the entries from our drop index are in there.

--clear the tran log
BACKUP LOG adventureworks  TO DISK = N'NUL' WITH NOFORMAT, NOINIT, NAME = N'adventureworks-LogBackup', 
SKIP, NOREWIND, NOUNLOAD, STATS = 10
--look at your log, verify it's clear
dbcc log (Adventureworks, 3)

You might see entries left over in your transaction log. Note those that were there before running the rest of this demo. We're going to drop the clustered index now.

BEGIN TRANSACTION DropIndex

IF  EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[HumanResources].[Department_test]') AND name = N'PK_Departmenttest_DepartmentID')
ALTER TABLE [HumanResources].[Department_test] DROP CONSTRAINT [PK_Departmenttest_DepartmentID]

COMMIT TRANSACTION DropIndex

Now, dump your transaction log into the LogInfo table we set up before.

BEGIN TRANSACTION LogInsert

INSERT INTO LogInfo
EXEC ('dbcc log (Adventureworks)')

COMMIT TRANSACTION LogInsert

Since I had some records in my LogInfo table from before the drop, I removed those from my table using the following query:

DELETE
--SELECT *
FROM LogInfo
WHERE
	currentLSN <= '00000367:0000003b:0001'

Now look at the entries that were generated during the drop index:

operation			context			cnt
LOP_SET_FREE_SPACE	LCX_PFS				904
LOP_SET_BITS		LCX_PFS				 24
LOP_DELETE_ROWS		LCX_MARK_AS_GHOST	         15
LOP_LOCK_XACT		LCX_NULL			 11
LOP_EXPUNGE_ROWS	LCX_CLUSTERED		          9
LOP_INSERT_ROWS		LCX_CLUSTERED	 	          6
LOP_EXPUNGE_ROWS	LCX_INDEX_LEAF		          6
LOP_HOBT_DDL		LCX_NULL			  5
LOP_MODIFY_ROW		LCX_CLUSTERED		          5
LOP_MODIFY_HEADER	LCX_PFS				  4
LOP_MODIFY_ROW		LCX_PFS				  4
LOP_INSERT_ROWS		LCX_INDEX_LEAF		          2
LOP_BEGIN_XACT		LCX_NULL			  1
LOP_ROOT_CHANGE		LCX_CLUSTERED		          1
LOP_MODIFY_ROW		LCX_IAM				  1
LOP_HOBT_DELTA		LCX_NULL			  1
LOP_COMMIT_XACT		LCX_NULL			  1

Looks to me like there were some records generated by the index drop. We freed quite a bit of space. My instincts were telling me that the LOP_SET_FREE_SPACE operation was related to the number of pages in the table. So I tested that hypothesis.

DECLARE @spaceused TABLE ( 
	name SYSNAME
	, [rows] INT
	, reserved VARCHAR(255)
	, data VARCHAR(255)
	, index_size VARCHAR(255)
	, unused VARCHAR(255)
)
	
INSERT INTO @spaceused
EXEC sp_spaceused [HumanResources.Department_test]


SELECT 
	(CAST(REPLACE(data, ' kb','') AS INT) * 1024 )/ 8192 AS dataPages
FROM @spaceused
/*--Results:
DataPages
904
*/

So we learned that dropping a clustered index on a table would result in one entry for every page of data in the table. So when the MSDN says no additional space is needed, they must be assuming you have enough space available in the log file to store a record for each page.

Now looking at the other log entries, there isn't a lot to note. I know the LOP_INSERT_ROWS operation has to do with the rows I inserted into the logInfo table, so we can ignore them. But the other operations LOP_SET_BITS, LOP_DELETE_ROWS, LOP_LOCK_XACT, etc... I'm not sure what they are doing. Google isn't exactly being forthcoming when I go to look up what these operations are.

But I was able to learn that log space will be required when dropping a clustered index. Later I'll research how much more space is needed if you have non-clustered indexes and drop the clustered index they depend on. I know it will be a significant increase in the number of rows inserted into the log file, I'm just not sure what magnitude it will be.

If you're still reading, I think you know why I wrote this blog. I'm studying the internals of the log file in SQL server. This has been an excersize to see how well I can extract useful knowledge from the log file in order to answer a real world question. If you're not looking to master SQL server, this blog has been way more information than you'll ever need to know. But if you are looking to master SQL Server, let me know. We may be able to help each other learn more!

Let me know what I can do to help!

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • A New File Interrogator
  • Using Generative AI in Data Engineering
  • Getting started with Microsoft Fabric
  • Docker-based Spark
  • Network Infrastructure Updates

Recent Comments

  1. slowder on Data Engineering for Databricks
  2. Alex Ott on Data Engineering for Databricks

Archives

  • July 2023
  • June 2023
  • March 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • October 2018
  • August 2018
  • May 2018
  • February 2018
  • January 2018
  • November 2017
  • October 2017
  • September 2017
  • August 2017
  • June 2017
  • March 2017
  • February 2014
  • January 2014
  • December 2013
  • November 2013
  • October 2013
  • August 2013
  • July 2013
  • June 2013
  • February 2013
  • January 2013
  • August 2012
  • June 2012
  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • December 2011
  • November 2011
  • October 2011
  • September 2011
  • August 2011
  • July 2011
  • June 2011
  • May 2011
  • April 2011
  • March 2011
  • February 2011
  • January 2011
  • December 2010
  • November 2010
  • October 2010
  • September 2010
  • August 2010
  • July 2010
  • June 2010
  • May 2010
  • April 2010
  • March 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • August 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009
  • March 2009
  • February 2009
  • January 2009
  • December 2008
  • November 2008
  • October 2008
  • September 2008
  • August 2008
  • July 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • November 2007
  • October 2007
  • September 2007
  • August 2007
  • July 2007
  • June 2007
  • May 2007
  • April 2007
  • March 2007
  • February 2007
  • January 2007
  • December 2006
  • November 2006
  • October 2006
  • September 2006
  • August 2006
  • July 2006
  • June 2006
  • May 2006
  • April 2006
  • March 2006
  • February 2006
  • January 2006
  • December 2005
  • November 2005
  • October 2005
  • September 2005
  • August 2005
  • July 2005
  • June 2005
  • May 2005
  • April 2005
  • March 2005
  • February 2005
  • January 2005
  • November 2004
  • September 2004
  • August 2004
  • July 2004
  • April 2004
  • March 2004
  • June 2002

Categories

  • Career Development
  • Data Engineering
  • Data Science
  • Infrastructure
  • Microsoft SQL
  • Modern Data Estate
  • Personal
  • Random Technology
  • uncategorized
© 2025 shannonlowder.com | Powered by Minimalist Blog WordPress Theme