web-dev-qa-db-fra.com

Verrouillage au niveau de la base de données

J'ai une instance de production de SQL Server 2014 sur laquelle je dois effectuer une maintenance légère.

Essentiellement, je dois remplacer le contenu de deux tables entières au sein d'une même transaction. Je souhaite empêcher quiconque d'interroger l'une ou l'autre des tables pendant la modification des données. Les tables sont petites et je m'attends à ce que l'opération prenne moins de quelques secondes.

Malheureusement, je n'ai pas l'avantage de temps d'arrêt prévu pour cela.

La question est donc de savoir comment verrouiller plusieurs objets à la fois - ou même la base de données entière?

Idéalement, je pourrais simplement prendre un verrou au niveau de la base de données, apporter les modifications et libérer le verrou, mais cela ne semble pas possible dans SQL Server 2014.

5
Sidawy

Vous pouvez d'abord utiliser une requête avec UPDLOCK, pour vous protéger de tout au long de la transaction (sauf les lectures sales).

Il ne peut jamais s'agir d'un seul verrou car un seul verrou ne peut pas s'étendre sur des objets. Mais je crois toujours que cela accomplit ce que vous recherchez, tant que vous n'avez pas de requêtes avec NOLOCK (et si vous le faites, vous obtenez exactement ce que vous avez demandé!).

BEGIN TRANSACTION;

SELECT pkcol FROM dbo.foo WITH (UPDLOCK, HOLDLOCK)
UNION ALL
SELECT pkcol FROM dbo.bar WITH (UPDLOCK, HOLDLOCK);

-- do other stuff

UPDATE dbo.foo SET ...;
UPDATE dbo.bar SET ...;

-- do other stuff

-- default isolation level users will be blocked until:
COMMIT TRANSACTION;

Il est possible qu'avec NOLOCK un utilisateur puisse se faufiler au milieu et interroger à partir des deux tables et obtenir des données de la première table après sa mise à jour et de la deuxième table avant sa mise à jour. Mais encore une fois, c'est ce que vous obtenez lorsque vous autorisez NOLOCK.

Et il est également possible qu'à ce moment-là, un utilisateur sous le niveau d'isolement par défaut puisse interroger bar et voir la valeur old, mais il se bloque sur foo.

11
Aaron Bertrand

Je vais sauter à contrecœur dans le train des écluses.

Si vous vouliez réellement verrouiller la base de données pour votre mise à jour, comme le dit votre titre, vous pourriez mettre la base de données en mode utilisateur unique et être assuré que seule votre connexion pourrait se connecter du tout pendant que vous effectuez des mises à jour:

ALTER DATABASE AdventureWorks2012
SET SINGLE_USER
GO

Et après vos mises à jour:

ALTER DATABASE whatever
SET MULTI_USER
GO

Soyez averti, cependant, que cela peut être délicat - par exemple, SSMS ouvre régulièrement de nombreuses connexions afin qu'il commence à mal se comporter dans ce mode. Votre meilleur pari est d'utiliser sqlcmd dans ce mode.

4
LowlyDBA