web-dev-qa-db-fra.com

Qu'est-ce qui déclenche exactement la MISE À JOUR de la colonne is_media_read_only sur sys.database_files?

Prêt à résoudre ce problème problème lié à une mauvaise valeur pour is_media_read_only propriété de la base de données J'ai fait quelques recherches et tests, mais à la fin je n'ai pas pu déterminer ce qui exactement déclenche la MISE À JOUR de la colonne is_media_read_only sur sys.database_files.

Selon sys.database_files documentation, la colonne is_media_read_only doit avoir l'une des deux valeurs possibles:

1 = Le fichier est sur un support en lecture seule.

0 = le fichier est sur un support en lecture-écriture.

Avec ces informations, j'ai fait l'expérience suivante avec deux versions différentes de SQL Server:

Microsoft SQL Server 2014 (SP3-GDR) (KB4505218) - 12.0.6108.1 (X64)
Microsoft SQL Server 2017 (RTM-CU16) (KB4508218) - 14.0.3223.3 (X64)

Branché une clé USB dans mon ordinateur portable (lecteur E :) et créé une base de données comme suit:

CREATE DATABASE [MyDB]
 ON  PRIMARY 
( NAME = N'MyDB_01', FILENAME = N'D:\DataBases\MyDB_01.mdf'), 
 FILEGROUP [SECONDARY] 
( NAME = N'MyDB_02', FILENAME = N'E:\DataBasesPendrive\MyDB_02.ndf')
 LOG ON 
( NAME = N'MyDB_log', FILENAME = N'D:\DataBases\MyDB_log.ldf')
GO

Requis sys.database_files:

USE MyDB;
GO
SELECT file_id, name, physical_name, is_media_read_only, is_read_only, state_desc  
FROM sys.database_files;
GO

Voici le résultat:

Query result before

Une fois la base de données créée, j'ai ouvert une invite CMD et j'ai exécuté diskpart. Sur l'utilitaire, j'ai émis les commandes suivantes:

list disk
select disk 2
attributes disk set readonly
attributes disk

DiskPart

Le disque 2 (ma clé USB) est maintenant un média en lecture seule , donc je m'attendais à ce que le is_media_read_only valeur à modifier, mais quand j'ai demandé sys.database_files encore une fois, il n'y a pas eu de changement: is_media_read_only était toujours à 0. J'ai donc commencé à faire des procédures aléatoires avec la base de données pour voir si quoi que ce soit pourrait faire remarquer à SQL Server que la base de données était maintenant assise sur un support en lecture seule et mettre à jour la valeur à 1. I pourrait y parvenir dans deux situations:

1er: passage de la base de données en mode READ_ONLY et retour en READ_WRITE. (il doit s'agir des deux actions, une seule d'entre elles ne fera pas l'affaire):

USE master;
GO
ALTER DATABASE MyDB SET READ_ONLY;
ALTER DATABASE MyDB SET READ_WRITE;
GO

2ème: détachez et rattachez à nouveau la base de données.

Ce sont les deux situations dans lesquelles j'aurais pu is_media_read_only mis à jour en 1 comme vous pouvez le voir sur l'image:

Query result after

Il était maintenant temps de rétablir la clé USB en lecture_écriture, donc je suis retourné à diskpart et j'ai couru:

select disk 2
attributes disk clear readonly

Lorsque j'ai changé le disque 2 pour lire à nouveau le mode d'écriture, le is_media_read_only serait uniquement mis à jour vers 0 lors d'une procédure de détachement et d'attachement. J'ai même essayé de redémarrer l'instance SQL Server en espérant qu'elle mettrait à jour la valeur, mais pas de chance.

Jusqu'à ce qu'un détachement et une attache de la base de données SQL Server me laisse la valeur 1 pour is_media_read_only même si le disque n'était plus READ_ONLY.

D'où mes questions: qu'est-ce qui déclenche exactement le UPDATE de la colonne is_media_read_only sur sys.database_files? Le comportement montré avec cette expérience pourrait-il être un bogue de SQL Server?

8
Ronaldo

Je suis ingénieur de l'équipe produit de SQL Server. Ce comportement multimédia en lecture seule n'est pas voulu par la conception et nous avons émis un correctif pour cela.

Pour décrire le comportement, la vérification des médias en lecture seule est effectuée lorsqu'un fichier est ouvert (par exemple, démarrage de la base de données, changement d'état de la base de données comme en lecture seule-> lecture-écriture). SQL conserve ensuite un indicateur de média en lecture seule pour un fichier en mémoire et celui-ci peut être conservé dans les métadonnées (sur le catalogue système). L'indicateur peut être conservé dans les métadonnées lorsque d'autres métadonnées de fichier sont modifiées ou lorsque l'état de la base de données change. Le vrai problème ici est qu'une fois qu'il a été durci sur les métadonnées (qui se trouvent sur le fichier de données principal), nous ne l'avons pas réinitialisé correctement, même le support n'est plus en lecture seule. Une condition qui peut réinitialiser l'indicateur est attachée, mais elle ne s'applique qu'aux fichiers de données secondaires.

Le comportement souhaité est que l'indicateur de média en lecture seule est désactivé lorsqu'un fichier est ouvert et que le média n'est plus en lecture seule. Ainsi, lorsqu'une base de données redémarre, son état change, elle est restaurée ou elle est attachée, le is_media_read_only devrait le refléter correctement pour chaque fichier.

Réparer

Le correctif est documenté avec KB Article 4538378 .

7
wonkim

La valeur semble être mise à jour lorsqu'une modification est tentée sur le fichier lui-même, comme l'a suggéré LowlyDBA. Mais uniquement lorsque le disque a été configuré pour lire uniquement lorsque plus aucune modification ne doit se produire sur le fichier de données secondaire. S'il y a encore des modifications à apporter, une erreur différente sera affichée.

Par exemple, lors de la création d'une base de données contenant un fichier de données sur F:\ Que nous définirons plus tard en lecture seule.

USE MASTER
GO
CREATE DATABASE Test
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'Test1', FILENAME = N'E:\Data\Test.mdf' , SIZE = 4160KB , MAXSIZE = UNLIMITED, FILEGROWTH = 16384KB ),
( NAME = N'testreadonly', FILENAME = N'F:\ReadonlyDisk\testreadonly.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 16384KB )
 LOG ON 
( NAME = N'Test_log', FILENAME = N'E:\Data\Test_Log.ldf' , SIZE = 1040KB , MAXSIZE = 2048GB , FILEGROWTH = 16384KB )
GO

Après avoir exécuté la ou les commandes diskpart, comme prévu, aucune modification n'est apportée à is_media_read_only:

USE Test
GO
select name,physical_name,is_media_read_only,is_read_only
from sys.database_files;

Résultat

name             physical_name                      is_media_read_only  is_read_only
Test1            E:\Data\Test.mdf                   0                    0
Test_log         E:\Data\Test_Log.ldf               0                    0
testreadonly     F:\ReadonlyDisk\testreadonly.ndf   0                    0

Si nous essayons d'augmenter la taille du fichier:

USE [master]
GO
ALTER DATABASE [Test] MODIFY FILE ( NAME = N'testreadonly', SIZE = 6144KB )
GO

J'ai remarqué que ça allait dans les deux sens, soit le message d'erreur que l'appareil n'est pas prêt:

Msg 5149, niveau 16, état 3, ligne 21 MODIFY FILE a rencontré l'erreur 21 du système d'exploitation (le périphérique n'est pas prêt.) Lors de la tentative de développement du fichier physique 'F:\ReadonlyDisk\testreadonly.ndf'.

Il s'agit d'un mauvais état, la base de données ne pourra pas non plus se déconnecter et se connecter à nouveau car le serveur SQL doit effectuer des modifications sur le fichier de données secondaire avant qu'il ne soit dans un état cohérent.

Le disque a été défini sur read_only alors que des modifications devaient encore être apportées au fichier de données secondaire.

L'autre message d'erreur indique que la base de données peut être à nouveau mise en ligne et hors ligne et que le serveur SQL connaît l'état du disque, mais aucune modification ne peut être apportée.

MODIFY FILE a rencontré l'erreur 19 du système d'exploitation (le support est protégé en écriture.) Lors de la tentative de développement du fichier physique 'F:\ReadonlyDisk\testreadonly.ndf'.

Lorsque ce deuxième message d'erreur se produit, par exemple en modifiant la taille du fichier, l'état sera mis à jour.

use master  
go
ALTER DATABASE [Test] MODIFY FILE ( NAME = N'testreadonly', SIZE = 10240KB )
GO

La colonne is_media_read_only Étant mise à jour:

name             physical_name                      is_media_read_only  is_read_only
Test1            E:\Data\Test.mdf                   0                    0
Test_log         E:\Data\Test_Log.ldf               0                    0
testreadonly     F:\ReadonlyDisk\testreadonly.ndf   1                    0

Lorsque vous placez le fichier .mdf Ou .ldf Sur un disque en lecture seule, la base de données n'est plus en ligne lors du redémarrage. Puisque ces fichiers sont modifiés dans l'étape Analyse de la récupération de la base de données.

Vous pouvez valider cela en créant une autre base de données, en mettant les 3 fichiers (.mdf, .ndf, .ldf) Sur le même disque et en le mettant hors ligne et en ligne à nouveau:

ALTER DATABASE [Test] SET OFFLINE

ALTER DATABASE [Test] SET ONLINE 

Avec .mdf et .ldf modifiés depuis la dernière connexion hors ligne -> En ligne

enter image description here

Donc, en théorie, vous pouvez placer le fichier secondaire sur le disque en lecture seule et la colonne is_media_read_only Sera mise à jour lorsque le serveur SQL sait qu'il se trouve sur un disque en lecture seule.

Il ne peut pas le savoir lors du redémarrage de la base de données ou de l'instance dans votre cas car aucune modification n'est apportée au fichier de données secondaire. Si des modifications telles que pendant le processus de récupération UNDO ou REDO doivent se produire dans votre fichier de date secondaire, votre base de données ne sera pas mise en ligne.

Lorsque vous essayez ceci sur un fichier .mdf Ou .ldf, Votre base de données ne sera pas en ligne et vous obtiendrez un message d'erreur comme

Erreur du système d'exploitation 19 (le support est protégé en écriture.) Sur le fichier "Emplacement du fichier" pendant FixupLogTail.

Puisqu'ils sont modifiés au démarrage de db.

Ainsi, nos deux expériences ont montré que is_media_read_only Change lors d'une modification de fichier. Cela semble incohérent, mais c'est un modèle d'une certaine manière. Avec cette conclusion, diriez-vous que ce problème dépasse le comportement "normal" de ce drapeau?

Eh bien, je dirais que toute modification de fichier réelle pourrait/déclencherait, mais si la modification de fichier doit se produire ou si la base de données n'est pas dans un état cohérent, la base de données ne se mettra tout simplement pas en ligne/d'autres problèmes surviendront. Si la modification échoue alors que la base de données est dans un état cohérent, comme la croissance manuelle du fichier, l'erreur se produit et le is_media_read_only Est mis à jour.

Et là encore, aucune modification de fichier n'est effectuée lors du changement du disque en lecture seule, en cours d'exécution

USE master;
GO
ALTER DATABASE Test SET READ_ONLY;
ALTER DATABASE Test SET READ_WRITE;
GO

Ensuite, changez le disque en lecture-écriture et exécutez à nouveau les deux instructions alter database:

enter image description here

Le fait de montrer que is_media_read_only Ne revient pas en arrière est dû au fait que le fichier n'est pas "testé" pour être à nouveau sur un disque inscriptible.

Oui, ce test. C'était comme ça: partie 1 - changer le lecteur en read_only; modifier la base de données en read_only; changez la base de données en read_write; is_media_read_only vaut 1 (parfait). partie 2 - changer le lecteur en read_write; modifier la base de données en read_only; changez la base de données en read_write; is_media_read_only est toujours égal à 1 (il aurait dû revenir à 0 pour prendre en charge la conclusion que toutes les modifications de fichier déclenchent la mise à jour de is_media_read_only).

Le fichier de données secondaire n'est pas modifié lors du changement de la base de données en lecture seule et inversement comme indiqué dans l'édition. Toutes les tentatives de modification de fichiers réelles modifient toujours l'état is_media_read_only.

L'état is_media_read_only N'a rien à voir avec les instructions alter qui ne modifient pas les fichiers secondaires, c'est exactement comment ces instructions alter se comportent.

Vous pouvez le tester vous-même en définissant la base de données en lecture seule et en lecture-écriture et en vérifiant la dernière date de modification sur les fichiers de données secondaires.

Si vous souhaitez savoir pourquoi la mise à jour est ensuite déclenchée lorsque le disque est configuré en lecture seule et que les commandes alter database s'exécutent sans tenter de modifier le fichier de données secondaire, je ne peux pas tester cette partie, aucune erreur n'est affichée ni trouvée dans le journal des erreurs lors de l'exécution des instructions. Cela pourrait avoir quelque chose à voir avec le fait que le serveur SQL n'essaie pas non plus de supprimer les fichiers de données secondaires qui se trouvent sur un disque avec is_media_read_only = 1 Lorsque la base de données est supprimée. Moins de possibilités d'erreur.

6
Randi Vertongen