是否建议SQL Server就地升级不如从前?


78

从SQL Server 6.5开始,我就一直在使用SQL Server进行断断续续的工作,至今仍然在我脑海中响起的那条老建议是永远不要进行就地升级。

我目前正在将我的2008 R2 DEV和TEST系统升级到SQL Server 2012,并且需要使用相同的硬件。不必还原我的Reporting Services配置的想法非常吸引人,我真的很不明智。没有涉及分析服务,也没有任何异常或非标准的服务-仅安装了数据库引擎和报告服务。

有没有人遇到就地升级的严重问题?还是应该重新评估就地升级的立场?


我选择在安装Reporting Services的1台服务器上进行就地升级。我遇到的唯一问题是尝试在本机客户端11的SSMS中使用导入导出工具。尝试转换失败,并出现有关无法识别的数据类型的错误。我使用的解决方法是保存程序包并在运行良好的SQL数据工具(BIDS替代)中运行。我认为这必须与SSIS 2008的配置文件不被覆盖有关。它发生在我之后,你可能只是能够改变本地客户端回到10
DamagedGoods

Answers:


92

答案很简单 -就位。之后,您可以查看配置并实施SQL Server 2012的最佳做法。

有关SQL Server升级/迁移的更长的答案

因此,这是一种观点,并不一定有错误或正确的答案,但出于很多原因,我更喜欢迁移样式升级而不是就地升级。话虽这么说-我的一些客户出于各种原因别无选择,只能进行就地升级。实际上,自SQL Server 2005以来,就地升级并没有以前那么糟糕。

为什么我更喜欢迁移到就地升级

  • 回滚更容易 -如果出现问题,您可以通过简单地说“我们中止了升级。请在解决此问题时将连接字符串更改为旧服务器”来回滚。使用就位时,您正在修理它或倒下了。
  • 刷新硬件 -硬件变化迅速。通过就地升级,您很容易陷入四年前适合您公司的硬件,而不适用于今天和未来四年的硬件。无论如何,您可能都必须在某个时候进行新硬件的迁移。
  • 感觉更好 -当然...这是主观的,但是您知道自己正在从新的OS安装开始进行,就感觉很好,您之前的工作人员(或者您知道之前知道的事情)之前都没有蛛网的新SQL安装今天),这可能会在将来引起您的头痛。
  • 新操作系统 -如果您今天的操作系统不是最新版本,那么迁移将使您有机会从新版本的操作系统开始。
  • 您可以对其进行测试 -是否曾经想过在安装SQL并将其与数据库和使用情况一起云化之前在新计算机上获得一组基准?您现在就可以这样做。
  • 有时,更容易掌握最佳实践 -也许SQL Server服务帐户是本地管理员。也许内置管理员是SA服务器角色。也许事情以前已经被黑客入侵才能使其正常工作。您可以修复所有问题并重新开始。
  • 免费测试环境和额外的睡眠 -在新环境启用之前,拥有一个可以在实际转换日之前工作的环境是一个很大的好处。迁移到新环境意味着您可以在工作时间(比实际转换日提前)构建它,并提前进行多种测试。您可以在所有应用程序和系统上运行几天的完整回归测试,并在真正完成最后一组还原/附加以及转换所有应用程序和访问新环境之前放心。
  • 您不必一次完成所有操作 -我碰到的一种非常常见的情况是,一个环境试图将其整合为几个实例。也许每个版本一个,也许每个“层”和版本一个。根据测试,项目计划和供应商认证的及时性,许多此类项目对于各种应用程序和数据库都有不同的时间表。进行迁移意味着您可以在准备就绪时移动那些准备就绪的数据库,并且仍然可以处理由于某种原因而无法移动的那些数据库的请求。

请注意,我并不是说您必须在迁移时这样做。如果您不打算在预算内购买新硬件,并且无法进行此升级,那么就地安装就可以正常工作。与6.5天相比,升级过程中的支持要好得多,因此这样做不会让您陷入困境。

如果您确实计划就地进行开发/测试,但想进行生产迁移,则可以考虑在生产前至少进行一次迁移。这样,您可以提前制定清单,并处理所有您没有想到的潜在问题。

附加/分离与备份/还原进行迁移

如果您决定采用迁移方法,那么还有另一个决定可能仍在争论中,那就是如何将数据库移至新环境。您可以将数据库与旧服务器分离,并将其附加到新服务器上,也可以备份并还原到那里。

我更喜欢备份/还原。我听到的关于分离/附加的最大优点是节省了一些时间。对我而言,备份/还原获胜有以下几个原因:

  • 保持旧的可访问性 -这允许您在源服务器上仍然具有可访问的数据库。分离/附加应该执行相同的操作,但是这将需要一些步骤,并且分离/附加可能存在人为错误的余地,这可能会使操作变得复杂。
  • 您可以保证拥有备份 - 确保已进行了备份,而不仅仅是从分离中获取数据库并可能会忘记备份步骤。
  • 人为错误 -如果删除错误的文件,忘记要发送文件的位置或搞乱了步骤,则为数据库移动数据和日志文件会带来很大的风险。现在,您可以通过复制而不是剪切来减轻这种情况(如果分离,则应该摆脱剪切和粘贴的习惯),但是您可能会变得一团糟。SQL Server不再锁定这些文件,并且很容易意外删除文件,这让我冒着风险。
  • 这是不是真的 -以一个备份和复制它是多一点的时间,但它不是那么多,我愿意支付额外的风险吧。实际上-使用完整的恢复模型和日志备份,您可以减少停机时间,以便进行转换,如下面的“如何使迁移方法更快”所述

如果您决定进行备份/还原-这意味着您的旧源数据库将仍然在线。我喜欢在备份后使该数据库脱机。在编写安全性,作业,链接服务器,证书,数据库邮件设置和其他实例范围的信息的脚本之后,有时我会更进一步,使整个SQL实例脱机。这样可以避免测试过程中有人说“一切看起来都不错!”的问题。一两天后才意识到他们一直在与旧服务器上的旧数据库通信。使这些数据库脱机或使整个实例脱机,可以防止那些误报及其造成的混乱。

如何使迁移方法更快

通过使用完整的恢复模型,您可以最大程度地减少从旧环境到新环境的转换所需的停机时间,从而在繁忙的生产环境中停机时间很少。基本上-通过还原最新的完整备份,任何差异备份和已指定的任何已执行日志备份来准备要迁移到的环境NORECOVERY-然后,要进行最终转换,您要做的就是还原尚未还原的日志备份,以及您希望还原的最终日志备份,指定WITH RECOVERY。通过这种方式,对于大型数据库,可以通过在停机时间窗口之前支付全部,差异和大部分日志还原的费用,从而大大减少实际的转换停机时间窗口。感谢在评论中指出这一点!

如何使就地升级更安全

选择就地方法时,您可以做一些事情来改善您的体验和结果。

  • 备份 -提前对您环境中的所有用户和系统数据库进行适当的备份,并确保它们是好的(我很偏执。我实际上会首先将它们还原到某个地方,以真正知道它们是好的。。可能会浪费您的时间。但是,如果发生灾难,您可能会感激自己。)编写出有关该环境中SQL和OS安装的所有配置信息。
  • 开始之前先进行良好的测试 -确认您拥有良好的环境和良好的数据库。您应该执行一些操作,例如查看错误日志并定期运行DBCC CHECKDB,但是在进行就地升级之前,是个不错的开始。提前解决所有问题。
  • 确保操作系统运行状况 -不仅要确保SQL 运行状况良好,还要确保服务器运行状况良好。您的系统或应用程序错误事件日志中是否存在任何严重错误?您的可用空间如何?
  • 为最坏的情况做准备 -前段时间我写了一篇博客文章,前提是如果您不为失败做准备- 您实际上正在失败做准备 ..我仍然相信。因此,请仔细考虑您可能遇到的问题,并提前进行相应处理。让自己陷入“失败”的思维定势,您将想到其他本来没有的事情。

升级或迁移清单的重要性

如果您决定进行升级(无论是进行升级还是迁移),则应认真考虑创建清单并在每个环境中使用该清单。您应该在此清单中包括很多内容,其中至少应包括以下内容:

  1. 在开始时 -做一些事情,例如执行测试升级,在最新的数据库兼容性级别上测试应用程序,并考虑提前运行SQL Server升级顾问之类的工具,以查看执行SQL之前需要完成的任务服务器升级或迁移。
  2. 前置步骤 -清理,操作系统任务,提前打补丁,为升级准备应用程序(清理关机,连接字符串工作),备份等。
  3. 升级/迁移步骤 -为使升级或迁移成功并按正确的顺序进行,您必须执行的所有操作。安装,更改(或不更改,取决于您的测试和方法)对数据库的兼容模式更改等。
  4. 发布迁移/升级步骤 -各种测试,发布新版本或新服务器配置选项,最佳实践实施,安全性更改等。
  5. 回滚步骤 -在整个过程中,您都应具有回滚步骤和里程碑。如果您能做到这一点并且发生了,您将怎么办?什么是“完全回滚”标准?以及如何进行回滚(更改反向连接字符串,更改回设置,返回到旧版本,如果安装到位,则重新安装,如果迁移,则指向旧服务器,等等)

然后让将要进行生产升级的人员在生产以外的某些环境中遵循清单,尤其是在可能的情况下关闭类似于生产的环境(如我所说,“生产南部” ...)并记录任何问题或要点他们由于缺少清单而不得不从清单中转移或即兴创作。然后合并更改,并与您的生产更改一起

我不能过分强调在迁移或升级后以及在迁移之前进行充分测试的重要性。在升级过程中做出回滚决定应该很容易-尤其是在迁移过程中。如果有什么不舒服的地方,请回滚并找出原因,以免在迁移过程中无法有效而可靠地进行故障排除。一旦您处于这个新环境中并与用户建立联系-回滚就成为一项艰巨的任务。您无法将SQL Server数据库还原到早期版本。这意味着手动工作和数据迁移。我总是等几个星期才能消除旧环境,但是您应该尽一切努力通过在您的实时用户接触新环境之前找到所有问题来避免使用旧环境。最好在您开始升级/迁移之前。

关于SQL Server Reporting Services迁移/升级的快速说明 迁移SSRS安装并不是很多人认为的艰巨任务。这篇technet / books在线文章实际上很方便。该文章中最重要的建议之一是“备份加密密钥”,尤其是当您保存了许多敏感信息(如计划的报告电子邮件接收者的电子邮件地址,多个连接的连接信息等)时。可以不时问我的一位客户,这有多重要。他们知道,因为我搞砸了这一步,并花了很多时间修改报告计划和连接字符串权限。


14

以我的经验,应该像以前一样进行相同的决策过程。AFAIK本身在MS SQL Server产品中还没有安装SQL Server的“世界改变者”,以及在推出具有数百万行代码的软件时可能遇到的潜在问题。可能会发生一些不良情况,现在您没有“ ROLLBACK”选项。

但是,您确实有其他选择。您可以考虑制作系统快照,在其他地方还原,执行升级并查看会发生什么。该测试应该给您带来很大的舒适感,但是不能绝对保证在产品包装盒上不会出现任何问题。但是,此选项在SQL 6.5天内不可用。

我只是假设最坏的情况。您执行就地升级,但失败很惨。然后,您必须在RTO和RCO中从中恢复。企业是否了解风险,您是否制定了减轻风险的计划?

如果这个生意做得不好,那么不建议这样做。


2

如果您的服务器在虚拟环境中运行,则可以在克隆上执行快照,然后应用就地升级并测试实例以验证升级是否成功。如果可行,您可以应用快照并使克隆成为生产服务器。如果处理不佳,则可以删除快照,然后返回升级前的映像以重试,或者删除克隆并进行完全迁移。


1
仅当存储也已虚拟化并且是快照的一部分时。如果存储直接连接到VM,则在恢复快照时不会“回滚” ...
Remus Rusanu 2013年

1

由于大量的硬件投资,我们被要求仅升级操作系统,同时保留当前的SQL Server版本(2012、3个服务器,22个实例,约300个数据库)。没有像镜像等复杂的设置。

由于未升级SQL Server,因此本示例与问题不完全匹配。我认为这仍然是一个不错的答案,因为显示的步骤实际上比真正的就地迁移要简单。

概述:连接外接驱动器以进行完整备份,主要是出于预防目的。实际上,只有模型和msdb会从外部驱动器恢复。ldf / mdf留在原处以进行分离/连接。数据库中引用了一些本地帐户。在OS中重新创建它们之后,将重新创建DB中的引用(因为SID可能会更改)。

接下来是对我们有用的步骤:

1)注意服务器级别的设置,这些设置将在步骤12(服务器角色)和18到23中恢复。

2)将SQL Server 2012修补到SP3(如果要还原任何系统数据库,则需要一致性)。

3)验证每个实例上的版本是否匹配。“选择@@ version”

4)通过运行此脚本来生成这6个脚本。如果实例很多,Redgate SQL Multiscript可以节省大量时间(将Tools-> Options => Line Length调整为最大值(8192),然后使用Text Output)。

  • 后备
  • 恢复
  • 分离
  • 连接
  • 重新创建登录
  • 将用户重新链接到登录名

    -- (1) BACKUP / (2) RESTORE
    --    
    --*** SET THESE to external drive location
    --*** and create the Destination Directories
    declare 
        @backupInstanceDir  varchar(300) = 'F:\ExternalDriveBackups\' + replace(@@servername, '\', '_'),
        @dateSuffix         varchar(100) = '2015-12-14'; 
    
    if (object_id('tempdb..DatabaseStatus') is not null)
    drop table #DAtabseSTatus;
    
    select 
        d.name DbName, 
        d.state_desc DbState,
        d.user_access_desc UserMode,
        convert(bit, (d.is_read_only * -1 + 1)) as IsWritable,
        d.is_trustworthy_on as IsTrustWorthy,
        d.is_in_standby IsInStandby,
        d.recovery_model_desc RecoveryModel,
        suser_sname(d.owner_sid) as Owner,
        convert(bit, 
            case when d.database_id <= 4 or d.is_distributor = 1
                then 1
                else 0
            end) as IsSystemDb,
        mf.type_desc as FileType,
        mf.name FileName,
        mf.state FileState,
        mf.state_desc FileStatDesc,
        mf.physical_name PhysicalName,
        mf.type as FileTypeId    
    into #DatabaseStatus
    from
        sys.master_files AS mf
    join sys.databases AS d
    ON  mf.database_id = d.database_id
    where
        1=1
    order by
        d.name,
        mf.physical_name;
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutBU
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutRE
    
    create table #sqlOutBU
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    create table #sqlOutRE
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutBU select char(10) + '-- BACKUP SCRIPT' + char(10);
    insert into #sqlOutRE select char(10) + '-- RESTORE SCRIPT' + char(10);
    
    
    insert into #sqlOutBU select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    insert into #sqlOutRE select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';        
    
    PRINT '--Script for Backing up all DBs in a SQL Server Instance to a specific location' 
    
    SET nocount ON 
    
    insert into #sqlOutBU select char(10) + 
    '--' + char(10) + '-- BACKUP ' + @@servername + '--' + char(10) + 
    'use [Master]; set deadlock_priority high;' + char(10);
    
    insert into #sqlOutRE select '
    -- RESTORE
    --
    -- BE SURE TO BACKUP SYSTEM DBS TO AN ALTERNATE LOCATION JUST BEFORE RESTORING!
    --
    use [Master]; set deadlock_priority high;' + char(10);
    
    DECLARE @dbname nvarchar(128) 
    declare dblist_cursor cursor fast_forward for 
    select [name] from master.sys.databases where [name] != 'tempdb'
    order by iif(database_id <= 4, '0', '1') + [name]
    
    open dblist_cursor 
    fetch next from dblist_cursor into @dbname 
    
    while @@fetch_status = 0 
    begin 
    
        declare @bak nvarchar(300) = @backupInstanceDir + '\' + @dbname + '_' + @dateSuffix + '.bak';
    
        insert into #sqlOutBU select char(10) + 'backup database [' + @dbname + '] to disk = ''' + @bak + ''' WITH COPY_ONLY, NOFORMAT, NOINIT, ' + char(10) + 
            'NAME = N''' + @dbName + '-Full'', SKIP, NOREWIND, NOUNLOAD, COMPRESSION, STATS = 25;';
    
        insert into #sqlOutRE select 'restore database [' + @dbName + '] from disk = ''' + @bak + ''' WITH FILE = 1,' + char(10) +
        (
            select '    move ''' + FileName + ''' to ''' + PhysicalName + '''' From #DatabaseStatus
            where FileType = 'Rows' and DbName = @dbName
        ) + ',' + char(10) +
        (
            select '    move ''' + FileName + ''' to ''' + PhysicalName + '''' From #DatabaseStatus
            where FileType = 'Log' and DbName = @dbName
        ) + ',' + char(10) +
        '    NOUNLOAD, REPLACE, STATS = 25;' + char(10);               
    
        fetch next from dblist_cursor into @dbname 
    end 
    
    close dblist_cursor 
    deallocate dblist_cursor 
    
    insert into #sqlOutBU select char(10) + 'go' + char(10);
    insert into #sqlOutRE select char(10) + 'go' + char(10);
    
    select Command from #sqlOutBU order by Row; -- BACKUP SCRIPT
    select Command from #sqlOutRE order by Row; -- RESTORE SCRIPT
    
    go
    
    
    
    --
    -- (3) DETACH  -  Org Author: Artemakis Artemiou
    --      
    
    if object_id('tempdb..#sqlOutDT') is not null
        drop table #sqlOutDT
    
    create table #sqlOutDT
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutDT select char(10) + '-- DETACH all DBs from a SQL Server Instance' + char(10);      
    
    insert into #sqlOutDT select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    SET nocount ON 
    
    insert into #sqlOutDT select char(10) + '--' + char(10) + '-- DETACH ' + @@servername + char(10) + '--' + char(10) + '
    use MAster; set deadlock_priority high;' + char(10) + char(10);
    
    DECLARE @dbname nvarchar(128) 
    DECLARE dblist_cursor CURSOR fast_forward FOR 
    SELECT [name] 
    FROM   master.sys.databases 
    WHERE  database_id > 4 
    
    OPEN dblist_cursor 
    FETCH next FROM dblist_cursor INTO @dbname 
    
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
        insert into #sqlOutDT select
        'alter database ' + @dbname + ' set single_user with rollback immediate;' + char(10) +
        'EXEC sp_detach_db ''' + @dbname + ''', ''true'';' + char(10);
        FETCH next FROM dblist_cursor INTO @dbname 
    END 
    
    CLOSE dblist_cursor 
    DEALLOCATE dblist_cursor 
    
    insert into #sqlOutDT select char(10) + 'go' + char(10);
    select Command from #sqlOutDT order by Row;
    
    go
    
    
    
    --
    -- (4) ATTACH  -  Org Author: Artemakis Artemiou
    --    
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutAT
    
    create table #sqlOutAT
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutAT select char(10) + '-- ATTACH ALL DBs to a SQL Server Instance' + char(10);
    
    insert into #sqlOutAT select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    SET NOCOUNT ON
    
    insert into #sqlOutAT select char(10) + '--' + char(10) + '-- ATTACH ' + @@servername + char(10) + '--' + char(10) + 
    'use MAster;' + char(10) + char(10);
    
    DECLARE @dbname nvarchar(128);
    
    DECLARE DBList_cursor CURSOR fast_forward FOR 
    select [name] from master.sys.databases where database_id > 4
    order by name;
    
    OPEN DBList_cursor
    
    FETCH NEXT FROM DBList_cursor 
    INTO @dbname
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
    
    declare @attach_TSQL_script varchar(max)
    set @attach_TSQL_script=''
    set @attach_TSQL_script=@attach_TSQL_script+'CREATE DATABASE ' + @dbname +' ON ' 
    
    declare @tsql varchar(max),@filename varchar(max)
    set @tsql='DECLARE DBFiles_cursor CURSOR FOR select [filename] from '+ @dbname + '.sys.sysfiles'
    
    execute (@tsql) 
    
    PRINT '--'+@dbname 
    
    OPEN DBFiles_cursor
    FETCH NEXT FROM DBFiles_cursor INTO @filename
    
    WHILE @@FETCH_STATUS = 0
    BEGIN   
    set @attach_TSQL_script=@attach_TSQL_script+ char(10)+'    (FILENAME = '''+ @filename +'''),' 
    FETCH NEXT FROM DBFiles_cursor INTO @filename
    END
    
    set @attach_TSQL_script=SUBSTRING(@attach_TSQL_script,0,len(@attach_TSQL_script))
    set @attach_TSQL_script=@attach_TSQL_script+ char(10) +'    FOR ATTACH;';
    
    insert into #sqlOutAT select @attach_TSQL_script + char(10);
    
    PRINT @attach_TSQL_script 
    PRINT ''
    
    CLOSE DBFiles_cursor
    DEALLOCATE DBFiles_cursor
    
    FETCH NEXT FROM DBList_cursor 
    INTO @dbname
    
    END 
    
    CLOSE DBList_cursor
    DEALLOCATE DBList_cursor
    
    insert into #sqlOutAT select char(10) + 'go' + char(10);
    select Command from #sqlOutAT order by Row;
    go
    
    
    
    --
    -- (5) GENERATE A 'RE-CREATE LOGINS' SCRIPT
    --
    -- This script was modified from a version that was designed to copy from one server to another:
    --      http://stackoverflow.com/a/5983773/538763
    --
    
    
    USE [master]
    
    if object_id('tempdb..#sqlOut') is not null
    drop table #sqlOut;
    
    create table #sqlOut
    (
    Command nvarchar(max) not null,
    Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOut select char(10) + '-- RECREATE LOGINS' + char(10);
    
    
    insert into #sqlOut select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    insert into #sqlOut select 'use Master;' + char(10);
    go
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    declare @Debug bit = 0;
    declare @PartnerServer varchar(100) = @@SERVICENAME;  -- use current server before it is shutdown (disabled below)
    
    declare
        @MaxID int,
        @CurrID int,
        @SQL nvarchar(max),
        @LoginName sysname,
        @IsDisabled int,
        @Type char(1),
        @SID varbinary(85),
        @SIDString nvarchar(100),
        @PasswordHash varbinary(256),
        @PasswordHashString nvarchar(300),
        @RoleName sysname,
        @Machine sysname,
        @PermState nvarchar(60),
        @PermName sysname,
        @Class tinyint,
        @MajorID int,
        @ErrNumber int,
        @ErrSeverity int,
        @ErrState int,
        @ErrProcedure sysname,
        @ErrLine int,
        @ErrMsg nvarchar(2048);
    
    declare @Logins Table (LoginID int identity(1, 1) not null primary key,
                        [Name] sysname not null,
                        [SID] varbinary(85) not null,
                        IsDisabled int not null,
                        [Type] char(1) not null,
                        PasswordHash varbinary(256) null)
    declare @Roles Table (RoleID int identity(1, 1) not null primary key,
                    RoleName sysname not null,
                    LoginName sysname not null)
    declare @Perms Table (PermID int identity(1, 1) not null primary key,
                    LoginName sysname not null,
                    PermState nvarchar(60) not null,
                    PermName sysname not null,
                    Class tinyint not null,
                    ClassDesc nvarchar(60) not null,
                    MajorID int not null,
                    SubLoginName sysname null,
                    SubEndPointName sysname null)
    
    Set NoCount On;
    
    If CharIndex('\', @PartnerServer) > 0
    Begin
    Set @Machine = LEFT(@PartnerServer, CharIndex('\', @PartnerServer) - 1);
    End
    Else
    Begin
    Set @Machine = @PartnerServer;
    End
    
    -- Get all Windows logins from principal server
    Set @SQL = 'Select P.name, P.sid, P.is_disabled, P.type, L.password_hash' + CHAR(10) +
        'From ' /*+ QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_principals P' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.sql_logins L On L.principal_id = P.principal_id' + CHAR(10) +
        'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And P.name <> ''sa''' + CHAR(10) +
        'And P.name Not Like ''##%''' + CHAR(10) +
        'and P.Name Not like ''NT SERVICE%''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', P.name) = 0;';
    
    Insert Into @Logins (Name, SID, IsDisabled, Type, PasswordHash)
    Exec sp_executesql @SQL;
    
    -- Get all roles from principal server
    Set @SQL = 'Select RoleP.name, LoginP.name' + CHAR(10) +
        'From '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_role_members RM' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + .*/ +'master.sys.server_principals RoleP' +
        CHAR(10) + char(9) + 'On RoleP.principal_id = RM.role_principal_id' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_principals LoginP' +
        CHAR(10) + char(9) + 'On LoginP.principal_id = RM.member_principal_id' + CHAR(10) +
        'Where LoginP.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And LoginP.name <> ''sa''' + CHAR(10) +
        'And LoginP.name Not Like ''##%''' + CHAR(10) +
        'And LoginP.name Not Like ''NT SERVICE%''' + CHAR(10) +
        'And RoleP.type = ''R''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', LoginP.name) = 0;';
    
    Insert Into @Roles (RoleName, LoginName)
    Exec sp_executesql @SQL;
    
    -- Get all explicitly granted permissions
    Set @SQL = 'Select P.name Collate database_default,' + CHAR(10) +
        '   SP.state_desc, SP.permission_name, SP.class, SP.class_desc, SP.major_id,' + CHAR(10) +
        '   SubP.name Collate database_default,' + CHAR(10) +
        '   SubEP.name Collate database_default' + CHAR(10) +
        'From '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_principals P' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_permissions SP' + CHAR(10) +
        CHAR(9) + 'On SP.grantee_principal_id = P.principal_id' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_principals SubP' + CHAR(10) +
        CHAR(9) + 'On SubP.principal_id = SP.major_id And SP.class = 101' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.endpoints SubEP' + CHAR(10) +
        CHAR(9) + 'On SubEP.endpoint_id = SP.major_id And SP.class = 105' + CHAR(10) +
        'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And P.name <> ''sa''' + CHAR(10) +
        'And P.name Not Like ''##%''' + CHAR(10) +
        'And P.name Not Like ''NT SERVICE%''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', P.name) = 0;'
    
    Insert Into @Perms (LoginName, PermState, PermName, Class, ClassDesc, MajorID, SubLoginName, SubEndPointName)
    Exec sp_executesql @SQL;
    
    --select * from @Logins;
    --select * from @Roles;
    --select * from @perms;
    
    
    Select @MaxID = Max(LoginID), @CurrID = 1
    From @Logins;
    
    While @CurrID <= @MaxID
    Begin
    Select @LoginName = Name,
        @IsDisabled = IsDisabled,
        @Type = [Type],
        @SID = [SID],
        @PasswordHash = PasswordHash
    From @Logins
    Where LoginID = @CurrID;
    
    --    If Not Exists (Select 1 From sys.server_principals
    --              Where name = @LoginName)
    Begin
    
        set @sql = char(10);
        set @sql += 'If Not Exists (Select 1 From sys.server_principals Where name = ''' + @LoginName + ''')' + char(10);
        set @sql += 'begin' + char(10) + '    ';
    
        Set @SQL += 'Create Login ' + quotename(@LoginName)
        If @Type In ('U', 'G')
        Begin
            Set @SQL = @SQL + ' From Windows;'
        End
        Else
        Begin
            Set @PasswordHashString = '0x' +
                Cast('' As XML).value('xs:hexBinary(sql:variable("@PasswordHash"))', 'nvarchar(300)');
    
            Set @SQL = @SQL + ' With Password = ' + @PasswordHashString + ' HASHED;  --, ';
    
            Set @SIDString = '0x' +
                Cast('' As XML).value('xs:hexBinary(sql:variable("@SID"))', 'nvarchar(100)');
            Set @SQL = @SQL + 'SID = ' + @SIDString + ';' + char(10);
        End
    
        set @sql += char(10) +
            '    print ''Created Login ' + @loginName  + ''';' + char(10) +
            'end' + char(10) +
            'else' + char(10) +
            convert(nvarchar(max), '    print ''Login ' + @loginName + ' already existed. '';') + char(10);
    
        If @Debug = 0
        insert into #sqlOut select @SQL;                      
        Else
        Print @SQL;
    
        If @IsDisabled = 1
        Begin
            Set @SQL = 'Alter Login ' + quotename(@LoginName) + ' Disable;'
            If @Debug = 0
                insert into #sqlOut select @SQL;                              
            Else              
                Print @SQL;              
        End
        End
    Set @CurrID = @CurrID + 1;
    End
    
    
    insert into #sqlOut select char(10) + 'use Master;' + char(10);
    
    Select @MaxID = Max(RoleID), @CurrID = 1
    From @Roles;
    
    While @CurrID <= @MaxID
    Begin
    Select @LoginName = LoginName,
        @RoleName = RoleName
    From @Roles
    Where RoleID = @CurrID;
    
    /*  If Not Exists (Select 1 From sys.server_role_members RM
                Inner Join sys.server_principals RoleP
                    On RoleP.principal_id = RM.role_principal_id
                Inner Join sys.server_principals LoginP
                    On LoginP.principal_id = RM.member_principal_id
                Where LoginP.type In ('U', 'G', 'S')
                And RoleP.type = 'R'
                And RoleP.name = @RoleName
                And LoginP.name = @LoginName)*/
    Begin
        If @Debug = 0
        Begin          
            insert into #sqlOut select 'Exec sp_addsrvrolemember @rolename = ''' + @RoleName + ''', @loginame = ''' + @LoginName + ''';';
        End
        Else
        Begin
            Print 'Exec sp_addsrvrolemember @rolename = ''' + @RoleName + ''',';
            Print '     @loginame = ''' + @LoginName + ''';';
        End
    End
    
    Set @CurrID = @CurrID + 1;
    End
    
    
    insert into #sqlOut select char(10) + 'use Master;' + char(10);
    
    
    Select @MaxID = Max(PermID), @CurrID = 1
    From @Perms;
    
    While @CurrID <= @MaxID
    Begin
    Select @PermState = PermState,
        @PermName = PermName,
        @Class = Class,
        @LoginName = LoginName,
        @MajorID = MajorID,
        @SQL = PermState + space(1) + PermName + SPACE(1) +
            Case Class When 101 Then 'On Login::' + QUOTENAME(SubLoginName)
                    When 105 Then 'On ' + ClassDesc + '::' + QUOTENAME(SubEndPointName)
                    Else '' End +
            ' To ' + QUOTENAME(LoginName) + ';'
    From @Perms
    Where PermID = @CurrID;
    
    /*If Not Exists (Select 1 From sys.server_principals P
                Inner Join sys.server_permissions SP On SP.grantee_principal_id = P.principal_id
                Where SP.state_desc = @PermState
                And SP.permission_name = @PermName
                And SP.class = @Class
                And P.name = @LoginName
                And SP.major_id = @MajorID)*/
    Begin
        If @Debug = 0
                insert into #sqlOut select @sql;                      
        Else          
            Print @SQL;          
    End
    
    Set @CurrID = @CurrID + 1;
    End
    
    
    select Command from #sqlOut as SqlOut order by Row;
    go
    
    
    --
    -- (6) Generate a script to Re-link all users to logins based on current state (before shutdown)
    --
    
    use Master;
    
    if object_id('tempdb..#sqlOut') is not null
    drop table #sqlOut;
    
    create table #sqlOut
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOut select char(10) + '-- RELINK USERS TO LOGINS' + char(10);
    
    insert into #sqlOut select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    declare @dbCmd varchar(8000) = '
    use ?;
    
    insert into #sqlOut select char(10) + ''use ?;'' + char(10);  
    
    with links as
    (
    select u.name as UserName,
        l.loginname as LoginName
        from sysusers u 
        join master..syslogins l
        on u.sid = l.sid        
    where u.name != ''dbo''
        and u.isSqlUser = 1 or l.isNtName = 1 or l.isNtGroup = 1
    )
    insert into #sqlOut 
    select ''alter user ['' + UserName + ''] with name = ['' + UserName + ''], login = ['' + LoginName + '']''
    from links
    ';    
    
    exec sp_MSforeachdb @dbCmd;
    
    select Command from #sqlOut order by Row;
    
    go

5)运行脚本以将包括系统(主数据库,msdb数据库,模型数据库)在内的所有数据库备份到外部驱动器。

6)运行脚本以分离所有数据库

7)C驱动器将重新格式化。如果LDF / MDF不在C上,则保留它们。

8)Windows Server 2012安装在C上

9)如果原始系统文件不在C驱动器中,则将LDF / MDF移开。

10)将重新安装SQL Server 2012并将其修补到SP3 a。重新创建系统用户/组帐户

11)将系统数据库备份到新位置或文件名(小心不要覆盖原始文件!)。

12)运行重新创建角色片段。就像是:

USE [master]
CREATE SERVER ROLE [SomeServerRole]
--ALTER SERVER ROLE [dbcreator] ADD MEMBER [SomeServerRole]
--ALTER SERVER ROLE [bulkadmin] ADD MEMBER [SomeServerRole]
-- ALTER SERVER ROLE [SomeServerRole] ADD MEMBER [SomeMemberOrRole]

13)运行重新创建登录脚本(如果恢复了登录,则不执行任何操作)

14)停止SQL Agent。

(可以在这里恢复师父,我们退缩了)。

15)使用上面的脚本附加mdf / ldf。一种。如果失败,请使用上面的脚本从bak手动还原。

16)尝试还原模型

17)确保SQL Agent已停止。还原MSDB(链接)如果失败,则需要重新创建作业+维护计划+邮件配置+操作员

18)打开用户登录脚本...

    a. If there are master users (rare?) then First Re-Create users for master since it was not restored:
        use master;       
        CREATE USER [ABC] FOR LOGIN [machine\ABC]

    b. Run the rest of the script

19)使服务代理能够匹配原始值SELECT名称is_broker_enabled FROM sys.databases;

    alter database MSDB set single_user with rollback immediate;
    ALTER DATABASE [MSDB] SET ENABLE_BROKER;
    alter database MSDB set multi_user;

20)启动SQL代理

21)将并行度阈值设置为原始值

22)将任何数据库设置调整为其原始值:

 declare @dbCmd varchar(8000) = '
      use ?;
      if db_name() not in (''master'', ''model'', ''tempdb'', ''msdb'')
      begin
             print ''Adjusting [?]...'';    
            alter database [?] set single_user with rollback immediate;
             aLTER AUTHORIZATION ON DATABASE::[?] to [sa];
            -- alter database [?] set trustworthy on;
            ALTER DATABASE [?] SET AUTO_CLOSE OFF WITH NO_WAIT;     
            alter database [?] set multi_user;
      end     
      else
             print ''Skipping [?]...'';
    ';    

    exec sp_MSforeachdb @dbCmd;

23)检查工作所有权:

select s.name as JobName, l.name as login, SUSER_SNAME(s.owner_sid) AS login2
from  msdb..sysjobs s 
left join master.sys.syslogins l on s.owner_sid = l.sid

如果还升级了SQL Server版本,我不认为可以还原模型和msdb数据库,因此由于https://support.microsoft.com/zh-cn/kb/264474而导致作业丢失

缺少了什么:

  • 主数据库中的原始用户(稀有?)
  • 服务器角色

0

两种方法本身都没有错-我都做过,而且两种结果通常都很好。

如果迁移方法存在问题,那不是技术问题:这是懒惰。我经常发现,一家公司尚未完全升级到xxxx版本的原因是,因为他们选择了摇摆式迁移,却从不走动以完成全部迁移的艰苦工作。现在,他们有两组或更多组服务器,而不是一组。

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.