web-dev-qa-db-ja.com

「データベースは移行中です」エラー

今日、既存のデータベースの上にデータベースを復元しようとしていましたが、SSMSでデータベースを右クリックしただけです->タスク->オフラインにして、データベースを復元できるようにしました。

小さなポップアップウィンドウが表示され、しばらくQuery Executing.....が表示された後、Database is in use cannot take it offlineと言うエラーがスローされました。そこから収集したデータベースへのアクティブな接続がいくつかあるので、次のクエリを実行しようとしました

USE master
GO
ALTER DATABASE My_DatabaseName
SET OFFLINE WITH ROLLBACK IMMEDIATE
GO

この時点でも、SSMSはQuery Executing.....をしばらく表示してから、次のエラーをスローしました。

Msg 5061, Level 16, State 1, Line 1
ALTER DATABASE failed because a lock could not be placed on database 'My_DatabaseName'. Try again later.
Msg 5069, Level 16, State 1, Line 1
ALTER DATABASE statement failed.

この後、SSMSを介してデータベースに接続できませんでした。 SSMSを使用してオフラインにしようとすると、次のエラーが表示されました。

Database is in Transition. Try later .....

この時点では、データベースにアクセスできず、同じエラーメッセージDatabase is in Transitionが返されました。

私は人々が同様の問題に直面していたいくつかの質問をグーグルで読んだところ、SSMSを閉じて再度開くことを推奨しました。私もそうしました。これは単なる開発サーバーだったので、SSMSを使用してデータベースを削除し、新しいデータベースに復元しました。

私の質問は、これを引き起こした可能性のあるものは何ですか?そして、どうすればこれが将来発生するのを回避でき、将来同じ状況になった場合は、データベース全体を削除する以外に修正する他の方法はありますか?

ありがとうございました

12
M.Ali

再現

  1. SSMSを開く
  2. 新しいクエリウィンドウに次のように入力します

    use <YourDatabase>;
    go
    
  3. オブジェクトエクスプローラー(SSMS)に移動し、<YourDatabase>-> Tasks-> Take Offlineを右クリックします。
  4. 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つのステップについては、以下のスクリーンショットを参照してください。

enter image description here

最もよく表示されるのは、オブジェクトエクスプローラーセッションが別のセッションによってブロックされていることです(blocking_session_idで示されています)。そのオブジェクトエクスプローラーセッションは、データベースで排他ロック(X)を取得しようとします。上記の再現の場合、オブジェクトエクスプローラーセッションには更新ロック(U)が付与され、排他ロック(X)に変換しようとしました。最初のクエリウィンドウで表されたセッションによってブロックされたwait_typeはLCK_M_Xでした(use <YourDatabase>はデータベースの共有ロック(S)を取得します)。

そして、このエラーはまだanotherセッションがロックを取得しようとしているために発生し、このエラーメッセージは、セッションへのアクセスを拒否して拒否します。別の状態(この場合、オンラインからオフラインへの移行の状態)に移行しようとしているデータベース。

次回はどうしますか?

まず、パニックにならないでくださいおよびデータベースのドロップを開始しないでくださいです。 why何が表示されているかを確認するには、(上記と同様の診断クエリを使用して)トラブルシューティングを行う必要があります。そのようなメッセージがある場合、または何かが「ハング」しているように見える場合は、並行性の欠如を自動的に想定し、ブロッキングの調査を開始する必要があります(sys.dm_tran_locksが適切なスタートです)。

余談ですが、ランダムなアクションをとる前に、問題の根本を見つけるのが最善であると私は本当に信じています。この操作だけでなく、予期しないすべての動作にも当てはまります。問題の原因は本当にであることがわかっているので、それが大した問題ではなかったことは明らかです。基本的にブロックチェーンがあり、親ブロッカーはKILLをオンにした可能性が最も高いものでした。または、セッションのリクエストで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で十分でしょう。

24
Thomas Stringer

SQL Server Management Studio(SSMS)を閉じて再度開くだけで問題が解決しました。

4

何もする必要はなく、プロセスを強制終了しますSqLWB.exeタスクマネージャからSQL Serverを開き、データベースを右クリックしてオフラインにします。それが機能しない場合は、セッションが終了した後、コマンドを入力します

ALTER DATABASE [Test4] SET OFFLINE WITH ROLLBACK IMMEDIATE

そしてオフライン。それは私のためにも働いたようにそれは機能します。

0
garima