Échec de SHRINKFILE - Pourquoi l'augmentation de la taille du fichier le résout-elle?

10

J'exécute certaines SHRINKFILEopérations pour nettoyer un tas de petits fichiers inutiles dans un groupe de fichiers. Pour l'un des rétrécissements, la commande ci-dessous entraîne une erreur:

DBCC SHRINKFILE (N'myfile' , EMPTYFILE)'

L'ID de fichier x de l'ID de base de données x ne peut pas être réduit car il est en cours de réduction par un autre processus ou est vide

Elle n'est ni vide ni rétrécie. Il est exécuté sur une base de données qui n'est actuellement utilisée par personne sauf moi. La réduction automatique n'est pas activée et ne l'a jamais été. Cependant, des rétrécissements manuels ont été effectués régulièrement sur cette base de données avant que je ne mette la main dessus, le cas échéant.

Sur SQLServerCentral , un fil d'il y a dix ans suggère d'ajouter quelques Mo au fichier car cela "réinitialise un compteur ou un commutateur interne qui lui indique qu'il n'est pas en train de se réduire maintenant".

Cela a fonctionné - génial. Mais quelqu'un peut-il expliquer plus en détail comment / pourquoi cela fonctionne en ce qui concerne les composants internes de SQL Server?

LowlyDBA
la source
1
Je ne pourrais pas vous dire la réponse, mais voter de manière positive est une astuce pratique pour savoir si je me heurterai à cette situation à l'avenir!
John Eisbrener
si vous pouvez reprocher peut-être un indicateur sur la page d'en-tête de fichier qui est défini lors d'une réduction?
Martin Smith
Oui, je pourrais peut-être donner un coup de feu sur une instance de test, mais c'était une prod, donc je n'ai certainement pas le luxe d'essayer de le reproduire là-bas.
LowlyDBA

Réponses:

5

J'ai fouillé dans la page d'en-tête du fichier, comme suggéré par Martin Smith dans les commentaires. Je pense que cela fait partie de la réponse, mais il s'agit principalement de spéculations basées sur l'observation des modifications des valeurs d'indicateur de page d'en-tête de fichier entre l'exécution de rétrécissements et d'autres opérations.


J'ai d'abord créé une base de données pour tester, y compris un groupe de fichiers secondaire:

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;
GO

J'ai regardé la "page 0" pour le fichier secondaire, qui est file_id 3:

DBCC TRACEON (3604);
GO
DBCC PAGE (N'Shrinkfile_Test', 3, 0, 3);

Il y a un champ appelé m_flagBitsqui a une valeur de 0x208.

Si je vide ce fichier:

DBCC SHRINKFILE (N'ShrinkFile_Test_Secondary' , EMPTYFILE);

Ce m_flagbitschamp reste le même ( 0x208). Pas si intéressant, mais maintenant je suis dans la situation que vous avez signalée: si j'essaie de vider à nouveau le fichier, j'obtiens cette erreur:

L'ID de fichier 3 de l'ID de base de données 19 ne peut pas être réduit car il est en cours de réduction par un autre processus ou est vide.

Je vais essayer d'agrandir le fichier (la solution qui a fonctionné pour vous):

ALTER DATABASE ShrinkFile_Test
MODIFY FILE
(
    NAME = ShrinkFile_Test_Secondary,
    SIZE = 1025KB
);
GO

Maintenant m_flagbitsest 0x8!

À ce stade, la vidange du fichier réussit à nouveau renvoie la valeur 0x208comme vous pouvez vous y attendre.

La chose que je trouve intéressante est que si je fais cela après avoir repoussé le fichier (la valeur des bits de drapeau AKA est 0x8):

USE [master]
GO
ALTER DATABASE [Shrinkfile_Test] MODIFY FILEGROUP [SECONDARY] READONLY
GO

Le fichier est marqué comme is_read_onlydans le sys.databasestableau et m_flagbitsest remis à 0x208. Il semble donc qu'un indicateur de niveau de fichier similaire soit défini lors de la réduction d'un fichier et lors de sa définition en lecture seule.

Ma meilleure supposition est que cette valeur est utilisée avec un autre indicateur (interne) pour indiquer qu'un fichier peut être réduit. Agrandir le fichier semble désactiver ce drapeau (au moins celui visible dans m_flagbits).

Josh Darnell
la source