永久分离数据库


Answers:


13

如果从实例分离数据库,则需要在操作系统级别上删除文件。比较安全的方法是删除数据库。

我建议在将数据库置于只读模式后进行数据库的最终备份(因为这将确保备份期间不会发生任何活动),然后通过删除数据库命令将其从系统中删除

完整的命令集看起来类似于以下内容:

-- 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

我赞成约翰的回答;我只想添加一些有关您可能要清理的其他项目的详细信息。

  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. 查找引用数据库的维护计划-如果未对其进行更新以删除丢失的数据库,则这些维护计划将失败。


数据库中的OS文件也仍然存在。对SQL Server环境没有影响,但是可能需要删除或存档它们以释放磁盘空间
CaM

@CaM:这是约翰的回答。John的建议是删除数据库而不是分离数据库,而在SQL Server中删除数据库意味着从文件系统中删除数据库文件。
Andriy M

1

所有主要要点均已涵盖。以下是我的2美分:

分离数据库绝不是永久解决方案,因为它打算用于将数据库文件移动到服务器内或另一台服务器上。如上所述,可以通过SSMS中的Delete选项或DROP database命令永久删除数据库。

通常,有意使数据库保持脱机状态并不断生成警报的数据库是我们分离并保留的数据库,直到可以将其永久删除(删除)为止。

预分离任务:运行sp_helpdb dbname以了解文件位置。

清理任务:

  1. 从它们所在的位置删除数据库的mdf,ndf和ldf文件。
  2. 考虑到保留期,需要删除数据库的旧备份文件或将其移动到另一台服务器。

除了Logins,Agent Jobs,Triggers和Max已经提到的要点外,这2个也可以查看。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.