web-dev-qa-db-ja.com

データベースレベルのロック

SQL Server 2014の運用インスタンスがあり、簡単なメンテナンスが必要です。

基本的に、1つのトランザクション内で2つのテーブル全体の内容を置き換える必要があります。データの変更が行われている間、誰もがどちらのテーブルにもクエリを実行できないようにしたいと思います。テーブルは小さく、操作には数秒もかかりません。

残念ながら、これには計画的なダウンタイムのメリットはありません。

だから問題は、一度に複数のオブジェクト、またはデータベース全体をロックするにはどうすればよいですか?

理想的には、データベースレベルのロックを取得し、変更を加えて、ロックを解放するだけで済みますが、SQL Server 2014ではそれができないようです。

5
Sidawy

最初にUPDLOCKでクエリを使用して、トランザクション全体(ダーティリードを除く)からすべてを保護できます。

単一のロックはオブジェクトにまたがることができないため、単一のロックになることはできません。しかし、NOLOCKを使用したクエリがない限り、これで目的を達成できると私は信じています(そうすると、要求したとおりの結果が得られます!)。

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;

NOLOCKを使用すると、ユーザーが途中で侵入して2つのテーブルからクエリを実行し、更新後の最初のテーブルと更新前の2番目のテーブルからデータを取得する可能性があります。しかし、繰り返しになりますが、NOLOCKを許可するとそれが得られます。

また、ある時点で、デフォルトの分離レベルのユーザーがbarにクエリを実行してold値を表示できても、fooでブロックされる可能性があります。

11
Aaron Bertrand

ロックバンドワゴンに渋々とジャンプします。

タイトルが言うように、実際に更新のためにデータベースをロックしたいのであれば、データベースを シングルユーザーモード にして、接続のみが接続できることを確認してくださいまったく更新中:

ALTER DATABASE AdventureWorks2012
SET SINGLE_USER
GO

そして更新後:

ALTER DATABASE whatever
SET MULTI_USER
GO

ただし、これは注意が必要な場合があることに注意してください。たとえば、SSMSは定期的に多くの接続を開くため、これらのモードでは動作が低下します。最善の策は、このモードでsqlcmdを使用することです。

4
LowlyDBA