web-dev-qa-db-ja.com

データベースを完全に切り離す

データベースがインスタンスから完全に切り離されている場合、実行する必要があるクリーンアップタスクはありますか?

10
cspell

インスタンスからデータベースをデタッチする場合は、ファイルのOSレベルの削除を実行する必要があります。安全な方法は、代わりにデータベースを削除することです。

私が提案するのは、読み取り専用モードにした後にデータベースの最終バックアップをとることです(これにより、バックアップ中にアクティビティが発生しないことが保証されます)。その後、データベースからデータベースを削除します Drop Database コマンド。

コマンドの完全なセットは次のようになります。

-- 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
13
John Eisbrener

私はジョンの答えに賛成しています。クリーンアップする必要のある他のアイテムの詳細を追加したいと思います。

  1. SQL Serverエージェントのジョブとアラートはデータベースを参照する場合があります。それらをクリーンアップすると、不要なエラーが報告されなくなります。

  2. データベース専用に作成されたログインをすべて削除します。次の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;
    
  3. そのデータベースのバックアップデバイスが存在する場合があります。それらを削除することは厳密には必要ありませんが、使用されていない場合は、将来の混乱の可能性を排除するために移動する必要があります。

  4. サーバーレベルのトリガーはデータベースを参照する場合があります。

  5. データベースを参照するメンテナンスプランを探します。欠落しているデータベースを削除するように更新されていない場合、これらは失敗します。

13
Max Vernon

すべての主要なポイントはすでにカバーされています。以下は私の2セントです。

データベースの切り離しは、サーバー内または別のサーバーにデータベースファイルを移動するために使用することを目的としていたため、永続的な解決策になることはありません。データベースを完全に削除するには、SSMSの[削除]オプションまたは上記のDROPデータベースコマンドを使用します。

通常、意図的にオフラインにしてアラートを生成し続けるデータベースは、完全に削除(削除)できるようになるまで切り離して保持するデータベースです。

切り離し前のタスク:sp_helpdb dbnameを実行して、ファイルの場所を確認します。

クリーンアップタスク:

  1. データベースのmdf、ndf、およびldfファイルを、それらが存在する場所から削除します。
  2. 保存期間を考慮して、データベースの古いバックアップファイルを削除するか、別のサーバーに移動する必要があります。

ログイン、エージェントジョブ、トリガー、およびMaxによる前述のポイント以外に、これら2つも確認できます。

1