gotchasqlMinor
SHRINKFILE Failure - Why does increasing file size resolve it?
Viewed 0 times
whyfilesizeresolveincreasingdoesshrinkfilefailure
Problem
I am running some
File ID x of database ID x cannot be shrunk as it is either being
shrunk by another process or is empty
It is not empty nor being shrunk. It is being run on a database not currently in use by anyone except myself. Auto shrink is not enabled and never was. However, there were manual shrinks performed on this database on a regular basis prior to me getting my hands on it, if that matters at all.
On SQLServerCentral, a thread from a decade ago suggests adding a few MB to the file because that "resets an internal counter or switch that tells it it's not in the middle of a shrink now."
This worked - awesome. But can anyone explain with greater detail how/why this works in regard to SQL Server internals?
SHRINKFILE operations to clean up a bunch of tiny, unnecessary files in a filegroup. For one of the shrinks, the command below results in an error:DBCC SHRINKFILE (N'myfile' , EMPTYFILE)'File ID x of database ID x cannot be shrunk as it is either being
shrunk by another process or is empty
It is not empty nor being shrunk. It is being run on a database not currently in use by anyone except myself. Auto shrink is not enabled and never was. However, there were manual shrinks performed on this database on a regular basis prior to me getting my hands on it, if that matters at all.
On SQLServerCentral, a thread from a decade ago suggests adding a few MB to the file because that "resets an internal counter or switch that tells it it's not in the middle of a shrink now."
This worked - awesome. But can anyone explain with greater detail how/why this works in regard to SQL Server internals?
Solution
I poked around in the file header page, as suggested by Martin Smith in the comments. I think this is part of the answer, but it's mostly speculation based on observing changes to the file header page flag values between performing shrinks and other operations.
First I created a database to test with, including a secondary filegroup:
The I looked at "page 0" for the secondary file, which is file_id 3:
There's a field called
If I empty this file:
That
File ID 3 of database ID 19 cannot be shrunk as it is either being shrunk by another process or is empty.
I'll try growing the file (the solution that worked for you):
Now
At this point, emptying the file again is successful returns the value to
The thing that I find interesting is that if I do this after growing the file back out (AKA flagbits value is
The file is marked as
My best guess is that this value is used along with some other (internal) flag to indicate that a file is eligible to be shrunk. Growing the file appears to un-set that flag (at least the one visible in
First I created a database to test with, including a secondary filegroup:
CREATE DATABASE [Shrinkfile_Test]
ON PRIMARY
(
NAME = N'Shrinkfile_Test',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\Shrinkfile_Test.mdf',
SIZE = 8192KB,
FILEGROWTH = 65536KB
),
FILEGROUP [SECONDARY]
(
NAME = N'ShrinkFile_Test_Secondary',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\ShrinkFile_Test_Secondary.ndf',
SIZE = 1024KB,
FILEGROWTH = 65536KB
)
LOG ON
(
NAME = N'Shrinkfile_Test_log',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\Shrinkfile_Test_log.ldf',
SIZE = 73728KB,
FILEGROWTH = 65536KB
)
GO
USE Shrinkfile_Test;
GOThe I looked at "page 0" for the secondary file, which is file_id 3:
DBCC TRACEON (3604);
GO
DBCC PAGE (N'Shrinkfile_Test', 3, 0, 3);There's a field called
m_flagBits that has a value of 0x208.If I empty this file:
DBCC SHRINKFILE (N'ShrinkFile_Test_Secondary' , EMPTYFILE);That
m_flagbits field stays the same (0x208). Not that interesting, but now I'm in the situation you reported: if I try to empty the file again, I get this error:File ID 3 of database ID 19 cannot be shrunk as it is either being shrunk by another process or is empty.
I'll try growing the file (the solution that worked for you):
ALTER DATABASE ShrinkFile_Test
MODIFY FILE
(
NAME = ShrinkFile_Test_Secondary,
SIZE = 1025KB
);
GONow
m_flagbits is 0x8!At this point, emptying the file again is successful returns the value to
0x208 as you might expect.The thing that I find interesting is that if I do this after growing the file back out (AKA flagbits value is
0x8):USE [master]
GO
ALTER DATABASE [Shrinkfile_Test] MODIFY FILEGROUP [SECONDARY] READONLY
GOThe file is marked as
is_read_only in the sys.databases table, and m_flagbits is set back to 0x208. So it appears there is some similar file-level flag set when shrinking a file and when setting it to read only.My best guess is that this value is used along with some other (internal) flag to indicate that a file is eligible to be shrunk. Growing the file appears to un-set that flag (at least the one visible in
m_flagbits).Code Snippets
CREATE DATABASE [Shrinkfile_Test]
ON PRIMARY
(
NAME = N'Shrinkfile_Test',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\Shrinkfile_Test.mdf',
SIZE = 8192KB,
FILEGROWTH = 65536KB
),
FILEGROUP [SECONDARY]
(
NAME = N'ShrinkFile_Test_Secondary',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\ShrinkFile_Test_Secondary.ndf',
SIZE = 1024KB,
FILEGROWTH = 65536KB
)
LOG ON
(
NAME = N'Shrinkfile_Test_log',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\Shrinkfile_Test_log.ldf',
SIZE = 73728KB,
FILEGROWTH = 65536KB
)
GO
USE Shrinkfile_Test;
GODBCC TRACEON (3604);
GO
DBCC PAGE (N'Shrinkfile_Test', 3, 0, 3);DBCC SHRINKFILE (N'ShrinkFile_Test_Secondary' , EMPTYFILE);ALTER DATABASE ShrinkFile_Test
MODIFY FILE
(
NAME = ShrinkFile_Test_Secondary,
SIZE = 1025KB
);
GOUSE [master]
GO
ALTER DATABASE [Shrinkfile_Test] MODIFY FILEGROUP [SECONDARY] READONLY
GOContext
StackExchange Database Administrators Q#227391, answer score: 5
Revisions (0)
No revisions yet.