再現
- SSMSを開く
新しいクエリウィンドウに次のように入力します
use <YourDatabase>;
go
- オブジェクトエクスプローラー(SSMS)に移動し、右クリック
<YourDatabase>
-> Tasks
->Take Offline
2番目の新しいクエリウィンドウを開き、次のように入力します。
use <YourDatabase>;
go
次のメッセージが表示されます。
メッセージ952、レベル16、状態1、行1
データベース「TestDb1」は移行中です。後でステートメントを試してください。
これが発生している理由は、以下のクエリと同様の診断クエリから確認できます。
select
l.resource_type,
l.request_mode,
l.request_status,
l.request_session_id,
r.command,
r.status,
r.blocking_session_id,
r.wait_type,
r.wait_time,
r.wait_resource,
request_sql_text = st.text,
s.program_name,
most_recent_sql_text = stc.text
from sys.dm_tran_locks l
left join sys.dm_exec_requests r
on l.request_session_id = r.session_id
left join sys.dm_exec_sessions s
on l.request_session_id = s.session_id
left join sys.dm_exec_connections c
on s.session_id = c.session_id
outer apply sys.dm_exec_sql_text(r.sql_handle) st
outer apply sys.dm_exec_sql_text(c.most_recent_sql_handle) stc
where l.resource_database_id = db_id('<YourDatabase>')
order by request_session_id;
それだけの価値があるので、このエラーを再現するのにオブジェクトエクスプローラーは必要ありません。同じ操作を試行するブロックされた要求が必要なだけです(この場合、データベースをオフラインにします)。T-SQLの3つのステップについては、以下のスクリーンショットを参照してください。
最もよく表示されるのは、オブジェクトエクスプローラーセッションが別のセッション(で示されているblocking_session_id
)によってブロックされていることです。そのオブジェクトエクスプローラーセッションはX
、データベースの排他ロック()を取得しようとします。上記の再現のケースでは、オブジェクトエクスプローラーセッションに更新ロック(U
)が付与され、排他ロック(X
)に変換しようとしました。LCK_M_X
最初のクエリウィンドウ(データベースのuse <YourDatabase>
共有ロック(S
)を取得)で表されるセッションによってブロックされたwait_typeがありました。
そして、このエラーは、ロックを取得しようとしているさらに別のセッションから発生し、このエラーメッセージは、別の状態(この場合はオンラインの状態)に移行しようとしているデータベースへのアクセスを取得するセッションの拒否を引き起こしますオフライン移行へ)。
次回はどうしますか?
まず、パニックになったり、データベースの削除を開始したりしないでください。あなたは見つけるために(上記のような類似した診断クエリで)トラブルシューティングのアプローチを取る必要があり、なぜあなたは何をしているシーイング見ています。そのようなメッセージがある場合、または何かが「ハング」しているように見える場合は、並行性の欠如を自動的に想定し、ブロッキングの調査を開始する必要があります(これsys.dm_tran_locks
は良いスタートです)。
余談ですが、ランダムなアクションをとる前に、問題の根源を見つけることが最善であると私は本当に信じています。この操作だけでなく、それは予期しないすべての動作に当てはまります。何が本当に問題を引き起こしているかを知っていれば、それが本当に大した問題ではなかったことは明らかです。基本的にはブロッキングチェーンがあり、親ブロッカーはおそらくKILL
onを発行した可能性が高いものでした。または、セッションの要求でありたくない場合はKILL
、完了するまで待機することもできます。どちらの方法でも、特定のシナリオ(ロールバックまたはコミットの待機)を考慮して、適切かつ慎重な決定を行うための知識がありました。
注目に値するもう1つのことは、これが常にGUIではなくT-SQLの代替案を選択する理由の1つです。T-SQLで何を実行しているのか、SQL Serverで何をしているのかを正確に把握できます。結局のところ、明示的なコマンドを発行しました。GUIを使用する場合、実際のT-SQLは抽象化されます。この場合、ブロックされたオブジェクトエクスプローラーがデータベースをオフラインにしようとする試みを調べましたALTER DATABASE <YourDatabase> SET OFFLINE
。ロールバックの試みはなかったため、無期限に待機していました。あなたのケースでは、そのデータベースがロックされているセッションをロールバックしたい場合は、ALTER DATABASE ... SET OFFLINE WITH ROLLBACK IMMEDIATE
ロールバックが大丈夫であると最初に判断した場合に十分でしょう。