Les mises à niveau sur place de SQL Server sont-elles aussi mal conseillées qu'auparavant?
Je travaille avec et hors serveur SQL depuis SQL Server 6.5, le vieux conseil qui résonne encore dans ma tête était de ne jamais faire de mise à niveau sur place.
Je suis en train de mettre à niveau mes systèmes 2008 R2 DEV et TEST vers SQL Server 2012 et je dois utiliser le même matériel. L'idée de ne pas avoir à restaurer ma configuration de Reporting Services est très attrayante et je suis vraiment contre le mur en termes de temps. Aucun service d'analyse n'est impliqué ou quelque chose d'inhabituel ou non standard - seuls le moteur de base de données et les services de génération de rapports sont installés.
Quelqu'un a-t-il rencontré de graves problèmes avec les mises à niveau sur place? Ou devrais-je réévaluer ma position concernant les mises à niveau sur place?
Réponse vraiment courte - En place, ça va. Vous pouvez ensuite revoir votre configuration et implémenter les meilleures pratiques pour SQL Server 2012.
Une réponse plus longue sur les mises à niveau/migrations SQL Server
C'est donc une opinion et il n'y a pas nécessairement de mauvaise ou de bonne réponse, mais je préfère les mises à niveau de style de migration à celles en place pour de nombreuses raisons. Cela étant dit - certains de mes clients pour diverses raisons n'ont pas eu d'autre choix que de faire une mise à niveau sur place et vraiment depuis SQL Server 2005, les mises à niveau sur place n'ont pas été aussi mauvaises qu'avant.
Pourquoi je préfère une migration vers une mise à niveau sur place
- Restauration plus facile - Si quelque chose ne va pas, vous pouvez annuler en disant simplement "nous avons abandonné la mise à niveau .. Veuillez changer les chaînes de connexion à l'ancien serveur pendant que nous résolvons cela" . Avec un 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 le matériel qui convenait à votre entreprise il y a 4 ans, mais pas pour aujourd'hui et les quatre prochaines années avec une mise à niveau sur place. Vous devrez probablement effectuer une migration à un moment donné de toute façon pour le nouveau matériel.
- Feel Better - Bien sûr ... Celui-ci est subjectif, mais il fait du bien de savoir que vous commencez avec une nouvelle installation de système d'exploitation, une nouvelle installation SQL sans toiles d'araignées de la personne au travail avant vous (ou vous avant de savoir ce que vous saviez aujourd'hui) qui pourraient vous causer des maux de tête à l'avenir.
- Nouveau système d'exploitation - Une migration vous donne la chance de commencer avec une nouvelle version du système d'exploitation si vous n'êtes pas sur la dernière et la meilleure aujourd'hui.
- Vous pouvez le tester - Vous avez toujours voulu obtenir un ensemble de lignes de base sur une nouvelle machine avant d'installer SQL et de le cloud avec des bases de données et l'utilisation? Vous pouvez le faire maintenant.
- Parfois, il est plus facile de se faufiler dans les meilleures pratiques - Peut-être que le compte de service SQL Server était un administrateur local. Peut-être que les administrateurs intégrés sont dans le rôle de serveur SA. Peut-être que les choses ont été en quelque sorte piratées ensemble pour le faire fonctionner auparavant. Vous pouvez résoudre tout cela et recommencer à zéro.
- Environnement de test gratuit et sommeil supplémentaire - C'est un grand avantage d'avoir un environnement dans lequel vous pouvez travailler avant le jour de basculement réel lorsque vous créez ce nouvel environnement vivre. Faire une migration vers un nouvel environnement signifie que vous pouvez le créer pendant les heures ouvrables, bien avant votre jour de basculement réel 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 faire le jeu final de restaurations/attachements et de couper toutes les applications et d'accéder au nouvel environnement.
- Vous n'êtes pas obligé de tout faire en même temps - Une situation très courante que je rencontre est un environnement qui essaie de se consolider en quelques exemples . Peut-être un par version, peut-être un par "niveau" et version. Un grand nombre de ces projets ont des délais différents pour diverses applications et bases de données en fonction des tests, des plans de projet et de la rapidité de certification des fournisseurs. La migration signifie que vous pouvez déplacer les bases de données qui sont prêtes, quand elles sont prêtes et toujours gérer les demandes pour les bases de données qui ne peuvent pas se déplacer pour une raison ou une autre.
Attention Je ne dis pas que vous avez pour le faire comme une migration . In-Place fonctionne et cela fonctionne bien si vous ne prévoyez pas d'acheter de nouveau matériel dans votre budget et que vous ne pouvez pas le faire pour cette mise à niveau. Le soutien dans le processus de mise à niveau est tellement meilleur qu'il ne l'était en 6,5 jours, vous ne vous mettez donc pas dans une mauvaise position en faisant cela.
Si vous prévoyez de faire sur place pour dev/test mais que vous souhaitez effectuer une migration pour la production, vous pouvez envisager de faire au moins une migration avant la production. De cette façon, vous pouvez travailler à l'avance sur votre liste de contrôle et traiter tout problème potentiel auquel vous ne pensiez pas.
Attacher/détacher ou sauvegarder/restaurer pour les migrations
Si vous décidez d'adopter l'approche de la migration, il y a encore une décision sur laquelle vous pouvez toujours 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 joindre au nouveau, soit la sauvegarder et la restaurer là-bas.
Je préfère la sauvegarde/restauration. Le plus grand avantage que j'entends à propos de détacher/attacher est qu'il fait gagner du temps. Pour moi, la sauvegarde/restauration gagne pour plusieurs raisons:
- Gardez l'ancien accessible - Cela vous permet d'avoir toujours une base de données accessible sur le serveur source. detach/attach devrait faire de même, mais cela nécessitera quelques étapes et il y a place pour une erreur humaine avec detach/attach qui pourrait compliquer cela.
- Vous garantissez que vous avez une sauvegarde - Au lieu de simplement prendre une base de données d'un détachement et d'oublier potentiellement une étape de sauvegarde, vous vous êtes assuré que vous 'ai pris cette sauvegarde.
- Erreur humaine - Si vous supprimez le mauvais fichier, oubliez où vous envoyez quelque chose ou gâchez vos étapes, vous risquez beaucoup en déplaçant les données et en vous connectant fichiers autour de 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 vous débarrasser de l'habitude de couper et coller), mais vous pourriez toujours gâcher. SQL Server ne verrouille plus ces fichiers et il est trop facile de supprimer un fichier accidentellement pour que je puisse le risquer.
- Ce n'est pas vraiment ça plus lent - Faire une sauvegarde et la copier c'est un peu plus de temps, mais ce n'est pas pas tant que je suis prêt à payer le risque supplémentaire pour cela. En fait - en utilisant le modèle de récupération complète et les sauvegardes de journaux, vous pouvez réduire encore le temps d'arrêt pour les coupures, comme décrit ci-dessous dans "Comment rendre l'approche de migration plus rapide"
Si vous décidez de faire 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 avoir effectué la sauvegarde. Je vais parfois plus loin et je déconnecte toute l'instance SQL après avoir é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 à l'échelle de l'instance. Cela évite un problème lors des tests où quelqu'un dit "Tout a l'air bien!" seulement pour réaliser un jour ou deux plus tard qu'ils ont parlé à l'ancienne base de données sur l'ancien serveur. Mettre ces bases de données hors ligne ou toute l'instance hors ligne vous permet d'éviter ces faux positifs et le gâchis qu'ils causent.
Comment accélérer l'approche de la migration
Vous pouvez minimiser les temps d'arrêt requis pour la transition d'un ancien à un nouvel environnement pour un environnement de production occupé avec peu de temps d'arrêt en utilisant le modèle de récupération complète. Fondamentalement - installez l'environnement vers lequel vous migrez en restaurant la dernière sauvegarde complète, toutes les sauvegardes différentielles et toutes les sauvegardes de journal déjà prises en spécifiant NORECOVERY
- alors tout ce que vous aurez à faire pour la transition finale est de restaurer les sauvegardes de journal qui n'ont pas encore été restaurés et la sauvegarde finale du journal que vous souhaitez restaurer en spécifiant WITH RECOVERY
. De cette façon, pour une grande base de données, la fenêtre d'indisponibilité de basculement réelle peut être considérablement réduite en payant le coût des restaurations complètes, différentielles 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 mesures que vous pouvez prendre pour améliorer votre expérience et vos résultats lors du choix de l'approche sur place.
- Sauvegarde - Effectuez à l'avance des sauvegardes appropriées de toutes les bases de données utilisateur et système de votre environnement et assurez-vous qu'elles sont bonnes (je suis paranoïaque. restaurez-les d'abord quelque part pour vraiment savoir qu'ils sont bons .. Peut-être perdez-vous votre temps .. Mais vous pouvez vous remercier en cas de catastrophe) .. Script toutes les informations de configuration sur l'installation SQL et OS dans cet environnement.
- Testez bien avant de commencer - Vérifiez que vous disposez d'un bon environnement et de bonnes bases de données. Vous devriez faire des choses comme regarder les journaux d'erreurs et exécuter DBCC CHECKDB régulièrement, mais avant de faire une mise à niveau sur place, c'est le bon moment pour commencer. Résolvez les problèmes à l'avance.
- Assurez 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. Y a-t-il des erreurs noueuses dans les journaux d'événements de votre système ou de votre application? Comment est votre espace libre?
- Préparez-vous au pire - J'ai eu une série de billets de blog il y a un moment qui partait du principe que si vous ne vous préparez pas à l'échec - vous préparez en fait à échouer .. Je le crois toujours. Réfléchissez donc aux problèmes que vous pourriez avoir et traitez-les en conséquence à l'avance. Mettez-vous dans la mentalité "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 de faire une mise à niveau (que ce soit en place ou en migration), vous devriez sérieusement envisager de créer une liste de contrôle et d'utiliser cette liste de contrôle dans chaque environnement. Vous devriez inclure un tas de choses dans cette liste de contrôle, notamment:
- Au démarrage - Faites des choses comme effectuer une mise à niveau de test, testez vos applications sur le dernier niveau de compatibilité de base de données et envisagez d'exécuter un outil comme le SQL Server Upgrade Advisor à l'avance pour voir quel type de tâches vous devez effectuer avant d'effectuer la mise à niveau ou la migration de SQL Server.
- Pré-étapes - Nettoyage, tâches du système d'exploitation, correctif à l'avance, préparation des applications pour la mise à niveau (arrêts propres, travail de la chaîne de connexion), sauvegardes , etc.
- Étapes de mise à niveau/migration - Tout ce que vous avez à faire pour que la mise à niveau ou la migration réussisse et dans le bon ordre. L'installation, la modification (ou la non-modification selon vos tests et votre approche) des modifications du mode de compatibilité dans les bases de données, etc.
- Étapes de post-migration/mise à niveau - Divers tests, publication d'une nouvelle version ou de nouvelles options de configuration de serveur, mise en œuvre des meilleures pratiques, changements de sécurité, etc.
- Étapes de restauration - Tout au long du processus, vous devez avoir des étapes de restauration et des jalons. Si vous arrivez aussi loin et que cela se produit, que ferez-vous? Quels sont les critères "faire une restauration complète"? Et comment faire cette restauration (inverser les changements de chaîne de connexion, changer les paramètres, revenir à l'ancienne version, réinstaller si c'est en place, pointer vers l'ancien serveur si une migration, etc.)
Et puis demandez à la personne qui effectuera la mise à niveau de la production de suivre la liste de contrôle dans un autre environnement que la production - en particulier celui qui ferme ressemble à la production si possible ("Sud de la prod", comme je le dis ...) et notez tous les problèmes ou points où ils ont dû s'écarter de la liste de contrôle ou improviser en raison d'un manque dans la liste de contrôle. Ensuite, fusionnez les changements et amusez-vous avec votre changement de production.
Je ne saurais trop insister sur l'importance de tester soigneusement après la migration ou la mise à niveau et avant votre migration suffisamment. 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 de mal à l'aise, annulez et déterminez si vous ne pouvez pas le dépanner efficacement et de manière fiable dans le feu de la migration. Une fois que vous êtes en direct dans 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 dans une version antérieure. Cela signifie un travail manuel et des migrations de données. J'attends toujours quelques semaines pour tuer l'ancien environnement, mais vous devez faire tout ce que vous pouvez pour éviter d'avoir besoin de cet ancien environnement en trouvant tous vos problèmes avant que vos utilisateurs en direct ne touchent le nouvel environnement. De préférence avant même de lancer la mise à niveau/migration.
Note 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 que beaucoup pensent. Ceci l'article en ligne Technet/Books est en fait assez pratique . L'un des avertissements les plus importants de cet article est "Sauvegarder les clés de chiffrement" , surtout si vous avez beaucoup d'informations sensibles enregistrées comme le rapport planifié e- adresses e-mail des destinataires, informations de connexion pour une multitude de connexions, etc. Ils le savent parce que j'ai gâché cette étape et passé beaucoup de temps à modifier les horaires des rapports et les autorisations de chaîne de connexion.
D'après mon expérience, le même processus de prise de décision devrait être fait que précédemment. AFAIK il n'y a pas eu de "changements du monde" avec l'installation de SQL Server, au sein du produit MS SQL Server en lui-même, et les problèmes potentiels que vous rencontrez lors du déploiement de logiciels avec des millions de lignes de code. Quelque chose de grave pourrait se produire et maintenant vous êtes coincé sans option 'ROLLBACK'.
Vous avez cependant d'autres alternatives en place. Vous pouvez envisager de créer un instantané du système, de restaurer ailleurs, d'effectuer la mise à niveau et de voir ce qui se passe. Ce test devrait vous donner beaucoup de confort, mais il ne garantit absolument aucun problème sur la boîte de prod. Cependant, il s'agit d'une option qui n'était pas disponible dans SQL 6.5 jours.
Je suppose simplement le pire des cas. Vous effectuez une mise à niveau sur place et elle échoue lamentablement. Vous devez ensuite récupérer de cela au sein de votre RTO et RCO. L'entreprise comprend-elle les risques et avez-vous des plans en place pour les atténuer?
Si l'entreprise n'est pas d'accord avec cela, alors ne le faites pas, ce serait mon conseil.
Si vos serveurs s'exécutent dans un environnement virtuel, vous pouvez effectuer un instantané sur un clone, puis appliquer la mise à niveau sur place et tester l'instance pour vérifier que la mise à niveau a réussi. Si cela fonctionne, vous pouvez appliquer l'instantané et faire du clone le serveur de production. En cas de problème, 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.
En raison d'un investissement matériel important, nous devions simplement mettre à niveau 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 mis à niveau. Je pense que c'est toujours une bonne réponse car les étapes indiquées seraient en fait plus simples qu'une véritable migration sur place.
Présentation: 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 disque externe. Les ldf/mdf ont été laissés en place pour détacher/attacher. Certains comptes locaux ont été référencés dans les bases de données. Après avoir été recréés dans le système d'exploitation, les références dans la base de données ont été recréées (car les SID peuvent changer).
Ensuite, voici les étapes qui ont fonctionné pour nous:
1) Prenez note des paramètres au niveau du serveur qui seront restaurés aux étapes 12 (Rôles du serveur) et 18 à 23.
2) Patch SQL Server 2012 à SP3 (cohérence requise si nous voulons restaurer n'importe quel dbs 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 énorme gain de temps s'il existe de nombreuses instances (Ajustez 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 toutes les bases de données, y compris le système (maître, msdb, modèle) sur un disque externe.
6) Exécuter un 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) Éloignez le LDF/MDF des fichiers système d'origine s'ils n'étaient pas sur le lecteur C.
10) SQL Server 2012 sera réinstallé et corrigé sur SP3 a. Recréer les comptes utilisateur/groupe du système
11) Sauvegardez les bases de données système vers un nouvel emplacement ou nom de fichier (attention à ne pas écraser les originaux!).
12) Exécutez l'extrait de rôle de recréation. 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écutez le script de recréation de connexion (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, restaurez manuellement à partir de bak en utilisant le script ci-dessus.
16) Tentative de restauration du modèle
17) Assurez-vous que l'agent SQL est arrêté. Restaurer MSDB (lien) a. En cas d'échec, vous devez recréer les travaux + le plan de maintenance + la configuration de la messagerie + les opérateurs
18) Ouvrir le script de l'utilisateur à la connexion ...
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) Activer Service Broker pour qu'il corresponde au nom SELECT de la valeur d'origine, 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émarrez l'agent SQL
21) Définir le seuil de parallélisme à sa valeur d'origine
22) Ajustez les paramètres de la 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érifier la propriété de l'emploi:
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, donc des travaux auraient été perdus en raison de https://support.Microsoft.com/en-us/kb/264474
Ce qui manque:
- Utilisateurs d'Orignal dans la base de données principale (rare?)
- Rôles de serveur
- ?
Rien n'est mal 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 migratoire, ce n'est pas technique: c'est la paresse. Trop souvent, je trouve que la raison pour laquelle une entreprise n'est pas encore complètement passée à la version xxxx est parce qu'elle a choisi une migration swing et qu'elle ne s'est jamais déplacée pour faire le travail difficile pour se déplacer complètement. Maintenant, ils ont deux ou plusieurs ensembles de serveurs au lieu d'un.