回答:
インスタンスからデータベースをデタッチする場合は、ファイルのOSレベルの削除を実行する必要があります。安全な方法は、代わりにデータベースを削除することです。
私が提案するのは、読み取り専用モードにした後でデータベースの最終バックアップをとることです(これにより、バックアップ中にアクティビティが発生しないことが保証されます)。その後、データベースの削除コマンドを使用してシステムからデータベースを削除します。
コマンドの完全なセットは次のようになります。
-- Use master db to ensure you don't have an active connection to the db you wish to affect
USE [master]
GO
-- This will kill any active transactions, but will force the database into a Read-Only state
ALTER DATABASE [db_name] SET READ_ONLY WITH ROLLBACK IMMEDIATE
GO
BACKUP DATABASE [db_name] -- Fill in more options here or use the UI to take a backup if you chooose
GO
-- This will kick out all connections from the database allowing you to drop it.
ALTER DATABASE [db_name] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
-- Drop the database (which automatically removes the files from the OS)
DROP DATABASE [db_name]
GO
この後、データベースに対してスクリプトを実行したジョブを探します。ジョブがデータベースを参照する方法はたくさんあるので(どれでも簡単に特定できるわけではありません)、失敗の結果を確認するまで待つことをお勧めします(その後、ジョブをスクリプトアウト/削除できます)。
最後に、このデータベースにのみアクセスできるインスタンスからユーザーを削除します。このスクリプトは、それらのユーザーが誰であるかを識別する必要がありますが、Maxのバージョンははるかにきれいです(これを含めるために私の回答を編集するまで、彼がアプローチを投稿したことに気付きませんでした)。
DECLARE @ExecString NVARCHAR (4000)
-- Create Empty Table in a very lazy manner
SELECT name, principal_id, CAST('' AS NVARCHAR(128)) as database_name
INTO ##tmp_AllDBUsers
FROM sys.server_principals
WHERE 1 = 2
-- Declare Cursor to iterate through all DBs on the instance
DECLARE dbCursor CURSOR
FOR
SELECT name
FROM sys .databases
DECLARE @name NVARCHAR (128)
OPEN dbCursor
FETCH NEXT FROM dbCursor
INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
SET @ExecString =
'USE [' + @name + '];
INSERT INTO ##tmp_AllDBUsers
SELECT sp.name, sp.principal_id, DB_NAME()
FROM sys.server_principals sp INNER JOIN sys.database_principals dp
ON sp.sid = dp.sid'
EXEC(@ExecString)
FETCH NEXT FROM dbCursor
INTO @name
END
-- Close and deallocate the cursor because you've finished traversing all it's data
CLOSE dbCursor
DEALLOCATE dbCursor
-- Show all logins that do not belong to a server-level role nor have access to any databases
SELECT sp.*
FROM sys.server_principals sp LEFT JOIN ##tmp_AllDBUsers adu
ON sp.principal_id = adu.principal_id
WHERE adu.principal_id IS NULL
AND sp.principal_id NOT IN (SELECT member_principal_id
FROM sys.server_role_members)
AND TYPE IN ('S', 'U', 'G')
-- cleanup
DROP TABLE ##tmp_AllDBUsers
私はジョンの答えに賛成しています。クリーンアップする必要のある他のアイテムの詳細を追加したいと思います。
SQL Serverエージェントのジョブとアラートはデータベースを参照する場合があります。それらをクリーンアップすると、不要なエラーが報告されるのを防ぐことができます。
データベース専用に作成されたログインをすべて削除します。次のT-SQLは、それらが使用されているかどうかを調べるために調査する可能性のある候補ログインを識別します。このコードは、どのデータベースからも参照されていないログインを識別します。
DECLARE @cmd nvarchar(max);
SET @cmd = ' SELECT sp.sid
FROM master.sys.server_principals sp
';
SELECT @cmd = @cmd + ' EXCEPT
SELECT dp.sid
FROM ' + QUOTENAME(d.name) + '.sys.database_principals dp
'
FROM sys.databases d
WHERE d.[state] <> 6; --ignore offline DBs
SET @cmd = 'SELECT spr.*
FROM (
' + @cmd + '
) src
INNER JOIN master.sys.server_principals spr
ON src.sid = spr.sid
WHERE spr.type <> ''R''
AND spr.name NOT LIKE ''%##MS_%''
AND spr.name NOT LIKE ''NT %''
AND NOT EXISTS (
SELECT 1
FROM sys.server_role_members srm
WHERE srm.member_principal_id = spr.principal_id
)
ORDER BY spr.name;
';
EXEC sys.sp_executesql @cmd;
そのデータベースのバックアップデバイスが存在する場合があります。それらを削除することは厳密には必要ありませんが、使用されていない場合は、将来の混乱の可能性を排除するために移動する必要があります。
サーバーレベルのトリガーはデータベースを参照する場合があります。
データベースを参照するメンテナンスプランを探します。欠落しているデータベースを削除するように更新されていない場合、これらは失敗します。
すべての主要なポイントはすでにカバーされています。以下は私の2セントです。
データベースの切り離しは、サーバー内または別のサーバーにデータベースファイルを移動するために使用することを目的としたものであるため、恒久的な解決策にはなりません。データベースを完全に削除するには、SSMSの[削除]オプションまたは上記のDROPデータベースコマンドを使用します。
通常、意図的にオフラインにしてアラートを生成し続けるデータベースは、完全に削除(削除)できるようになるまで切り離して保持するデータベースです。
切り離し前のタスク:実行sp_helpdb dbname
してファイルの場所を確認します。
クリーンアップタスク:
ログイン、エージェントジョブ、トリガー、およびMaxによる既述のポイント以外に、これら2つも確認できます。