Les mises à niveau sur place de SQL Server sont-elles aussi mal avisées qu'elles l'étaient auparavant?

78

Je travaille avec SQL Server depuis et vers SQL Server 6.5, le vieux conseil qui me retient toujours de ne pas faire de mise à niveau sur place.

Je suis en train de mettre à niveau mes systèmes R2 DEV et TEST 2008 vers SQL Server 2012 et je dois utiliser le même matériel. L'idée de ne pas avoir à restaurer la configuration de mes services de génération de rapports est très attrayante et je suis vraiment à la hauteur. Il n’existe aucun service d’analyse impliqué, ni quelque chose d’inhabituel ou de non standard: seuls le moteur de base de données et les services de reporting sont installés.

Quelqu'un at-il rencontré des problèmes graves avec les mises à niveau sur place? Ou devrais-je réévaluer ma position sur les mises à niveau sur place?

Marchandises endommagées
la source
J'ai choisi d'effectuer une mise à niveau sur place sur un serveur avec l'installation des services de génération de rapports. Le seul problème que j'ai rencontré concernait l'utilisation de l'outil d'exportation d'importation dans SSMS avec le client natif 11. La tentative de transformation a échoué avec une erreur concernant les types de données non reconnus. la solution de rechange que j'ai utilisée consistait à enregistrer le package et à l'exécuter dans les outils de données SQL (remplacement de BIDS), ce qui a bien fonctionné. Je pense que cela doit être lié au fait que le fichier de configuration de SSIS 2008 n’est pas écrasé. Cela m'est
arrivé

Réponses:

92

Réponse vraiment courte - En place, c'est bien. Vous pouvez ensuite revoir votre configuration et mettre en œuvre les meilleures pratiques pour SQL Server 2012.

Une réponse plus longue sur les mises à niveau / migrations SQL Server

Il s’agit donc d’une question d’opinion et il n’ya pas forcément de bonne ou de mauvaise réponse, mais je préfère les mises à niveau de migration par rapport aux systèmes en place pour de nombreuses raisons. Cela dit, certains de mes clients, pour diverses raisons, n’ont eu d’autre choix que de procéder à une installation sur place et, en réalité, depuis SQL Server 2005, les mises à niveau sur place n’ont plus été aussi mauvaises qu’avant.

Pourquoi je préfère une migration à une mise à niveau sur place

  • Restauration plus facile - Si quelque chose ne va pas, vous pouvez l'annuler en disant simplement "nous avons abandonné la mise à niveau .. Veuillez modifier les chaînes de connexion sur l'ancien serveur pendant que nous résolvons ce problème". Avec un système en place, vous le réparez ou vous êtes en panne.
  • Actualiser le matériel - Le matériel change rapidement. Vous pouvez facilement rester bloqué sur du matériel adapté à votre entreprise il y a 4 ans, mais pas à aujourd'hui et aux quatre prochaines années avec une mise à niveau sur place. De toute façon, vous devrez probablement effectuer une migration pour le nouveau matériel.
  • Feel Better - Sure ... C’est subjectif, mais cela fait du bien de savoir que vous commencez avec une nouvelle installation de système d’exploitation, une nouvelle installation de SQL sans sites Web de la personne au travail avant vous (ou avant vous saviez ce que vous saviez aujourd'hui) qui pourrait éventuellement vous causer des maux de tête à l'avenir.
  • Nouveau système d'exploitation - Une migration vous donne la possibilité de commencer avec une nouvelle version du système d'exploitation si vous ne possédez pas la version la plus récente et la plus performante du moment.
  • Vous pouvez le tester - Vous souhaitez toujours obtenir un ensemble de lignes de base sur une nouvelle machine avant d'installer SQL et de le nuancer avec des bases de données et son utilisation? Vous pouvez le faire maintenant.
  • Il est parfois plus facile d’utiliser les meilleures pratiques - Le compte de service SQL Server était peut-être un administrateur local. Peut-être que Builtin Administrators est dans le rôle de serveur SA. Peut-être que les choses ont été en quelque sorte mélangées pour que cela fonctionne auparavant. Vous pouvez réparer tout cela et recommencer à zéro.
  • Environnement de test gratuit et sommeil supplémentaire - Avoir un environnement dans lequel vous pouvez travailler avant le jour du basculement lorsque vous faites vivre ce nouvel environnement constitue un avantage considérable. Effectuer une migration vers un nouvel environnement signifie que vous pouvez le créer pendant les heures de bureau, bien avant votre journée de basculement, et le tester de nombreuses façons à l’avance. Vous pouvez exécuter des tests de régression complets sur toutes les applications et tous les systèmes pendant des jours et avoir une grande tranquillité d'esprit avant de procéder à la dernière série de restaurations / attaches et de basculement de toutes les applications et de l'accès au nouvel environnement.
  • Vous n'êtes pas obligé de tout faire en même temps - une situation très courante dans laquelle je me heurte est un environnement qui tente de se consolider à quelques occasions seulement. Peut-être un par version, peut-être un par "niveau" et version. Un grand nombre de ces projets ont des calendriers différents pour diverses applications et bases de données en fonction des tests, des plans de projet et de la rapidité de la certification du fournisseur. Effectuer la migration signifie que vous pouvez déplacer les bases de données prêtes, quand elles le sont et tout en gérant les demandes de ces bases de données qui ne peuvent pas être déplacées pour une raison ou une autre.

Remarquez que je ne dis pas que vous devez faire cela en tant que migration. Le service sur place fonctionne bien si vous ne prévoyez pas acheter le nouveau matériel dans votre budget et que vous ne pouvez pas le faire pour cette mise à niveau. Le support dans le processus de mise à niveau est tellement meilleur qu’il ne l’était dans les 6.5 jours, vous ne vous mettez donc pas dans une mauvaise position.

Si vous envisagez de créer sur place pour dev / test, mais que vous souhaitez effectuer une migration pour la production, vous pouvez envisager d'effectuer au moins une migration avant la production. De cette façon, vous pouvez préparer votre liste de contrôle à l’avance et régler tout problème potentiel auquel vous ne pensiez pas.

Attach / Detach vs. Sauvegarde / Restauration pour les migrations

Si vous décidez d'adopter l'approche de la migration, il reste encore une décision sur laquelle vous pouvez encore avoir un débat et c'est la façon dont vous déplacez votre base de données vers le nouvel environnement. Vous pouvez soit détacher votre base de données de l'ancien serveur et la relier au nouveau ou la sauvegarder et la restaurer à cet emplacement.

Je préfère la sauvegarde / restauration. Le plus gros avantage que j'entends parler de détachement / attachement est le gain de temps. Pour moi, la sauvegarde / restauration gagne pour plusieurs raisons:

  • Conserver l'ancien accessible - Cela vous permet de conserver une base de données accessible sur le serveur source. detach / attach devrait faire la même chose, mais cela nécessiterait quelques étapes et une erreur humaine avec détachement / attachement pourrait compliquer les choses.
  • Vous garantissez que vous disposez d'une sauvegarde - Au lieu de simplement extraire une base de données et éventuellement d'oublier une étape de sauvegarde, vous vous êtes assuré d'avoir effectué cette sauvegarde.
  • Erreur humaine - Si vous supprimez le mauvais fichier, oubliez où vous envoyez quelque chose ou si vous gâchez vos étapes, vous risquez beaucoup en déplaçant les données et les fichiers journaux pour votre base de données. Maintenant, vous pouvez atténuer cela en copiant au lieu de couper (et si vous vous détachez, vous devriez sortir de l’habitude couper-coller), mais vous pourriez continuer à faire des dégâts. SQL Server ne verrouille plus ces fichiers et il est trop facile de supprimer accidentellement un fichier pour que je puisse le risquer.
  • Ce n'est pas vraiment si lent - Faire une copie de sauvegarde et la copier, c'est un peu plus de temps, mais ce n'est pas pour autant que je suis prêt à en assumer le risque supplémentaire. En fait, en utilisant un modèle de récupération complète et des sauvegardes de journal, vous pouvez réduire encore le temps d'indisponibilité pour les transferts, comme indiqué ci-dessous dans la section "Procédure de migration rapide".

Si vous décidez d'effectuer la sauvegarde / restauration, cela signifie que votre ancienne base de données source sera toujours en ligne. J'aime mettre cette base de données hors ligne après la sauvegarde. Parfois, je vais encore plus loin et je mets l'ensemble de l'instance SQL hors ligne après que j'ai écrit la sécurité, les travaux, le serveur lié, les certificats, les paramètres de messagerie de la base de données et d'autres informations relatives à l'instance. Cela évite un problème pendant les tests où quelqu'un dit "Tout va bien!" seulement un jour ou deux plus tard, ils réalisent qu'ils ont parlé à l'ancienne base de données sur l'ancien serveur. Mettre ces bases de données hors ligne ou l'ensemble de l'instance hors ligne vous permet d'éviter ces faux positifs et les dégâts qu'ils causent.

Comment rendre l'approche de migration plus rapide

Vous pouvez réduire le temps d'arrêt requis pour passer d'un ancien environnement à un autre dans un environnement de production chargé avec un temps d'indisponibilité réduit en utilisant le modèle de récupération complète. Fondamentalement - mettez en scène l’environnement dans lequel vous migrez en restaurant la dernière sauvegarde complète, toutes les sauvegardes différentielles et toutes les sauvegardes de journal déjà effectuées en spécifiant NORECOVERY- il vous suffira ensuite de restaurer les sauvegardes de journal non encore restaurées et la sauvegarde finale du journal que vous souhaitez restaurer en spécifiant WITH RECOVERY. Ainsi, pour une base de données volumineuse, il est possible de réduire considérablement la fenêtre d'indisponibilité de la commutation en prenant en charge le coût de la restauration complète, différentielle et de la plupart des journaux avant la fenêtre d'indisponibilité. Merci à Tao de l' avoir signalé dans les commentaires!

Comment rendre la mise à niveau sur place plus sûre

Quelques choses que vous pouvez faire pour améliorer votre expérience et vos résultats lors du choix de l'approche sur place.

  • Sauvegarde - Faites des sauvegardes appropriées de toutes les bases de données utilisateur et système de votre environnement à l'avance et assurez-vous qu'elles sont bonnes (je suis paranoïaque. Je les restaurerais en premier lieu pour vraiment savoir qu'elles sont bonnes. Peut-être perdrez-vous votre temps. Mais vous pouvez vous remercier en cas de sinistre) .. Écrivez toutes les informations de configuration relatives à l'installation de SQL et du système d'exploitation dans cet environnement.
  • Testez les choses bien avant de commencer - Vérifiez que vous disposez d'un bon environnement et de bonnes bases de données. Vous devriez, par exemple, consulter les journaux des erreurs et exécuter DBCC CHECKDB de manière régulière, mais avant de procéder à une mise à niveau sur place, il est temps de commencer. Résoudre les problèmes à l'avance.
  • Assurer la santé du système d'exploitation - Ne vous contentez pas de vous assurer que SQL est sain, assurez-vous que votre serveur est sain. Des erreurs gnarly dans votre journal des événements d'erreur système ou d'application? Comment est votre espace libre?
  • Préparez-vous au pire - il y a quelque temps, j'ai eu une série d'articles sur le blog qui partait du principe que si vous ne vous préparez pas à l'échec, vous vous préparez en fait à échouer . Je le crois toujours. Alors réfléchissez aux problèmes que vous pourriez avoir et traitez-les en conséquence à l’avance. Obtenez-vous dans l'état d'esprit "d'échec" et vous penserez à des choses que vous n'auriez pas autrement.

L'importance des listes de contrôle de mise à niveau ou de migration

Si vous décidez d'effectuer une mise à niveau (en place ou de migration), vous devez sérieusement envisager de créer une liste de contrôle et de l'utiliser dans chaque environnement. Vous devriez inclure un tas d'éléments dans cette liste de contrôle, notamment:

  1. Au début - Effectuez certaines tâches, comme effectuer une mise à niveau test, testez vos applications au niveau de compatibilité de base de données le plus récent et envisagez d'exécuter un outil tel que le Conseiller de mise à niveau SQL Server à l' avance pour déterminer le type de tâches à effectuer avant d'effectuer l' exécution SQL. Mise à niveau ou migration du serveur.
  2. Pré-étapes - Nettoyage, tâches du système d'exploitation, correction à l'avance, préparation des applications pour la mise à niveau (arrêts propres, travail de la chaîne de connexion), sauvegardes , etc.
  3. Étapes de mise à niveau / migration - Tout ce que vous devez faire pour que la mise à niveau ou la migration aboutisse et dans le bon ordre. Installation, modification (ou modification en fonction de vos tests et de votre approche) des modifications du mode de compatibilité des bases de données, etc.
  4. Étapes post-migration / mise à niveau - Divers tests, publication d'une nouvelle version ou de nouvelles options de configuration du serveur, implémentation conforme aux meilleures pratiques, modification de la sécurité, etc.
  5. Étapes de restauration - Tout au long du chemin, vous devriez avoir des étapes de restauration et des jalons. Si vous en arrivez là et que cela se produise, que ferez-vous? Quels sont les critères "faire un retour en arrière complet"? Et comment procéder à cette annulation (modifications de chaîne de connexion inversée, modification des paramètres, retour à l'ancienne version, réinstallation éventuelle, remplacement de l'ancien serveur lors d'une migration, etc.)

Et ensuite, demandez à la personne qui effectuera la mise à niveau de la production de suivre la liste de contrôle dans un environnement autre que celui de la production - en particulier celui qui se ferme ressemble si possible à la production ("South of prod", comme je le dis ...) et notez tout problème ou tout point où ils ont dû se détourner de la liste de contrôle ou improviser à cause d’un manque dans la liste de contrôle. Ensuite, fusionnez les modifications et amusez-vous avec votre modification de la production.

Je ne saurais trop insister sur l’importance de tester suffisamment la post-migration ou la mise à niveau et suffisamment avant votre migration. Prendre une décision de restauration au milieu d'une mise à niveau devrait être facile, en particulier lors d'une migration. S'il y a quelque chose d'inconfort, revenez en arrière et déterminez si vous ne pouvez pas le résoudre efficacement et de manière fiable dans le feu de la migration. Une fois que vous êtes connecté à ce nouvel environnement et que les utilisateurs se connectent, la restauration devient une tâche difficile. Vous ne pouvez pas restaurer une base de données SQL Server vers une version antérieure. Cela signifie un travail manuel et des migrations de données. J'attends toujours quelques semaines pour éliminer l'ancien environnement, mais vous devez faire tout ce qui est en votre pouvoir pour ne pas avoir besoin de cet environnement en trouvant tous vos problèmes avant que vos utilisateurs ne touchent jamais le nouvel environnement. De préférence avant même de lancer la mise à niveau / migration.

Remarque rapide sur la migration / mise à niveau de SQL Server Reporting Services La migration d' une installation SSRS n'est pas une tâche herculéenne comme beaucoup le pensent. Cet article en ligne de technet / books est en fait assez pratique . L'un des avertissements les plus importants de cet article est "Sauvegardez les clés de cryptage", en particulier si vous avez beaucoup d'informations confidentielles enregistrées, telles que les adresses électroniques des destinataires d'e-mails avec rapport programmé, les informations de connexion pour une multitude de connexions, etc. peut demander à un de mes clients de temps en temps à quel point c'est important. Ils le savent parce que j'ai raté cette étape et passé beaucoup de temps à modifier les plannings de rapports et les autorisations de chaîne de connexion.

Mike Walsh
la source
14

D'après mon expérience, le même processus de prise de décision devrait être pris comme avant. Autant que je sache, il n'y a pas eu de «monde changeant» avec l'installation de SQL Server, dans le produit MS SQL Server en lui-même, et les problèmes potentiels que vous rencontrez lorsque vous déployez un logiciel avec des millions de lignes de code. Quelque chose de mauvais pourrait arriver et maintenant vous êtes bloqué sans option 'ROLLBACK'.

Vous avez cependant d'autres alternatives en place. Vous pouvez envisager de créer un instantané du système, de le restaurer ailleurs, d'effectuer la mise à niveau et de voir ce qui se passe. Ce test devrait vous apporter beaucoup de confort, mais il ne garantit pas absolument qu'aucun problème ne se produira sur le boîtier de commande. Cependant, il s'agit d'une option qui n'était pas disponible dans SQL 6.5 jours.

Je supposerais juste le pire des cas. Vous effectuez une mise à niveau sur place et elle échoue lamentablement. Vous devez ensuite récupérer cela dans votre RTO et votre RCO. L'entreprise comprend-elle les risques et avez-vous des plans en place pour les atténuer?

Si cela ne vous convient pas, alors ne le faites pas, ce serait mon conseil.

Ali Razeghi
la source
2

Si vos serveurs s'exécutent dans un environnement virtuel, vous pouvez effectuer une capture instantanée sur un clone, puis appliquer la mise à niveau sur place et tester l'instance pour vérifier que la mise à niveau a abouti. Si cela fonctionne, vous pouvez appliquer l'instantané et rendre le serveur de production cloné. Si cela se passe mal, vous pouvez supprimer l'instantané et revenir à l'image de pré-mise à niveau pour réessayer, ou supprimer le clone et effectuer une migration complète.

Troie
la source
1
Uniquement si le stockage est également virtualisé et fait partie de l'instantané. Si le stockage est directement connecté à la machine virtuelle, il ne sera pas "annulé" lors de la restauration de l'instantané ...
Remus Rusanu
1

En raison d'un investissement matériel important, nous avons dû mettre à niveau uniquement le système d'exploitation tout en conservant la version actuelle de SQL Server (2012, 3 serveurs, 22 instances, ~ 300 bases de données). Aucune configuration complexe comme la mise en miroir, etc.

Cet exemple ne correspond pas exactement à la question, car SQL Server n'est pas en cours de mise à niveau. Je pense que cela reste une bonne réponse car les étapes indiquées seraient en réalité plus simples qu'une migration en place.

Vue d'ensemble: Un lecteur externe a été connecté pour effectuer des sauvegardes complètes principalement par mesure de précaution. Seuls le modèle et msdb seront réellement restaurés à partir du lecteur externe. Les ldf / mdf ont été laissés en place pour le détachement / l’attachement. Certains comptes locaux ont été référencés dans les bases de données. Une fois qu'ils ont été recréés dans le système d'exploitation, les références de la base de données ont été recréées (car les identificateurs de sécurité peuvent changer).

Ensuite, voici les étapes qui ont fonctionné pour nous:

1) Prenez note des paramètres de niveau serveur qui seront restaurés aux étapes 12 (Rôles du serveur) et 18 à 23.

2) Corrigez SQL Server 2012 vers SP3 (cohérence nécessaire pour restaurer les fichiers système).

3) Vérifiez que les versions correspondent sur chaque instance. "Sélectionnez @@ version"

4) Générez ces 6 scripts en exécutant ce script. Redgate SQL Multiscript est un gain de temps considérable s’il ya plusieurs instances (réglez les outils -> Options => longueur de ligne au maximum (8192), puis utilisez la sortie texte).

  • Sauvegarde
  • Restaurer
  • Détacher
  • Attacher
  • Recréer les connexions
  • Relier les utilisateurs aux connexions

    -- (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) Exécutez le script pour sauvegarder tous les DB, y compris le système (maître, msdb, modèle) sur un lecteur externe.

6) Exécuter le script pour détacher toutes les bases de données

7) Le lecteur C sera reformaté. Conservez les LDF / MDF s'ils n'étaient PAS sur C.

8) Windows Server 2012 est installé sur C

9) Déplacez le fichier LDF / MDF des fichiers système originaux hors du chemin s’ils ne se trouvaient pas sur le lecteur C.

10) SQL Server 2012 sera réinstallé et corrigé vers le SP3 a. Recréer des comptes utilisateur / groupe du système

11) Sauvegardez les bases de données système dans un nouvel emplacement ou un nouveau nom de fichier (veillez à ne pas écraser les originaux!).

12) Exécutez le fragment de rôles recréé. Quelque chose comme:

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) Exécuter le script de connexion de recréation (ne fait rien si les connexions ont été restaurées)

14) Arrêtez SQL AGENT.

(Pourrait restaurer le Maître ici, nous nous sommes dégonflés).

15) Attachez mdf / ldf en utilisant le script ci-dessus. une. En cas d'échec, restaurer manuellement à partir de bak à l'aide du script ci-dessus.

16) Tentative de restauration du modèle

17) Assurez-vous que SQL Agent est arrêté. Restaurer MSDB (lien) a. En cas d'échec, nécessité de recréer des travaux + plan de maintenance + configuration de la messagerie + opérateurs

18) Ouvrir le script User To Login ...

    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) activez Service Broker pour qu'il corresponde à la valeur d'origine SELECT nom, 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) Démarrer l'agent SQL

21) Définir le seuil de parallélisme à la valeur d'origine

22) Ajustez les paramètres de base de données à leurs valeurs d'origine:

 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) Vérifiez la propriété du travail:

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

Si la version de SQL Server avait également été mise à niveau, je ne pense pas que le modèle et les bases de données msdb auraient pu être restaurés. Des travaux auraient donc été perdus en raison de https://support.microsoft.com/en-us/kb/264474.

Ce qui manque

  • Utilisateurs originaux dans la base de données master (rare?)
  • Rôles de serveur
  • ?
crokusek
la source
0

Rien ne va pas avec l'une ou l'autre approche en soi - j'ai fait les deux et les deux résultats sont généralement bons.

S'il y a un problème avec l'approche de migration, ce n'est pas technique: c'est de la paresse. Trop souvent, je trouve que la raison pour laquelle une entreprise n’a pas encore complètement adopté la version xxxx est qu’elle a choisi une migration de migration et qu’elle n’a jamais eu la possibilité de faire le travail difficile qui s’imposait. Maintenant, ils ont deux ou plusieurs ensembles de serveurs au lieu d'un.

RowlandG
la source