Migration d'une base de données vers une ancienne version de MS SQL Server



Vous disposez d'une base de donnĂ©es MS SQL Server que vous devez transfĂ©rer vers un autre ordinateur physique. Vous avez dĂ©jĂ  effectuĂ© une sauvegarde et vous ĂȘtes heureux de vous lancer dans une rĂ©cupĂ©ration. Mais il s'avĂšre que sur l'ordinateur sur lequel vous souhaitez transfĂ©rer la base de donnĂ©es, une ancienne version de MS SQL Server est installĂ©e. Stack Overflow vous assure que tout va mal. Mais est-ce vraiment le cas?


Bien sĂ»r, le transfert d'une base de donnĂ©es d'une version plus rĂ©cente vers une ancienne n'est pas un scĂ©nario classique et pas le plus correct. Mais souvent, les bases de donnĂ©es sont créées de maniĂšre Ă  prendre en charge de plus en plus de nouvelles versions de SQL, Ă  commencer par certaines, par exemple, 2008 R2, car la compatibilitĂ© directe avec MS SQL est plus qu'excellente. Et, par exemple, votre client a dĂ©jĂ  installĂ© MS SQL 2016 pour lui-mĂȘme, et vous avez MS SQL 2014 installĂ© sur votre serveur de test pour le dĂ©veloppement. Et vous souhaitez Ă©tendre votre base de clients pour savoir oĂč il y a confusion des donnĂ©es.

Microsoft a reniĂ© le problĂšme - ils disent qu'ils n'ont pas de compatibilitĂ© descendante et qu'il n'y a pas de faillite. La sauvegarde créée sur le serveur le plus rĂ©cent ne peut pas ĂȘtre restaurĂ©e sur l'ancien serveur. Oui, ils ont des outils comme DTS, copier une base de donnĂ©es, exporter-importer, etc. Mais ils sont si gĂȘnants et encombrants que le transfert normal d'une grande base de donnĂ©es avec de nombreuses tables pour les utiliser n'est pas particuliĂšrement pratique. En tout cas, personnellement, je n'ai pas rĂ©ussi.

Oui, vous pouvez générer des scripts SQL pour la base de données entiÚre, y compris les données. Mais imaginez, vous avez un tas de champs d'objets blob contenant des données volumineuses dans la base de données, et en général la taille de la base de données entiÚre est de 500+ Go. Imaginez combien un tel script prendra, combien de temps il sera généré et exécuté.

Ainsi, la tùche consiste à recréer avec précision la base de données (structure et données) à partir de la nouvelle version de MS SQL Server dans l'ancienne version. J'ai trouvé une solution assez simple que je veux partager. Bien sûr, cette solution a un nombre important de limitations, mais à mon avis, elle est toujours meilleure que DTS et les scripts.

La limitation numĂ©ro un est que vous avez besoin d'accĂ©der via MS SQL Management Studio aux deux serveurs - anciens et nouveaux. Si cela n'est pas possible, cela devrait ĂȘtre possible sur la machine Ă  partir de laquelle vous souhaitez transfĂ©rer la base de donnĂ©es, installez la version de SQL dans laquelle vous devez transfĂ©rer la base de donnĂ©es afin de transfĂ©rer d'abord la base de donnĂ©es localement vers cette version, puis faites-la glisser via la sauvegarde ou directement via * df fichiers de base de donnĂ©es (via DĂ©tacher / Attacher) Ă  la nouvelle machine (la version de SQL Server dans ce cas correspondra dĂ©jĂ ).

Une autre limitation est que vous aurez besoin d'un script de schĂ©ma de base de donnĂ©es (tous les objets, y compris les tables, les index, les constantes, les procĂ©dures stockĂ©es, les dĂ©clencheurs, etc.) sans donnĂ©es, et les instructions pour crĂ©er des contraintes de clĂ© Ă©trangĂšre doivent aller dans ce script Ă  la toute fin, sĂ©parĂ© du script pour crĂ©er les tables elles-mĂȘmes.

Je dĂ©crirai briĂšvement l'algorithme de transfert de donnĂ©es lui-mĂȘme. Toutes les actions sont effectuĂ©es dans une session Management Studio connectĂ©e au serveur vers lequel vous souhaitez transfĂ©rer la base de donnĂ©es.

1) Sur le nouveau serveur, crĂ©ez une base de donnĂ©es vide avec les mĂȘmes fichiers et groupes de fichiers que la base de donnĂ©es portable.

2) En utilisant le script de schéma de base de données, nous créons tous les objets de base de données (tables, index, vues, déclencheurs, procédures et fonctions stockées), mais sans créer de contraintes de clé étrangÚre. Vous ne pouvez pas créer FK à ce stade, car ils interféreront avec l'insertion des données.

3) Nous connectons la base de donnĂ©es Ă  partir de laquelle nous transfĂ©rerons les donnĂ©es en tant que serveur liĂ©, afin que vous puissiez utiliser l'ancienne base de donnĂ©es dans les requĂȘtes vers la nouvelle base de donnĂ©es.

EXEC sp_addlinkedserver @server=N'LinkedServerAlias', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'LinkedServerHost\LinkedServerName'; EXEC sp_addlinkedsrvlogin 'LinkedServerUser', 'false', null, 'RealUser', 'RealUserPassword'; 

4) Parce que les structures de base de donnĂ©es sont les mĂȘmes, nous utiliserons la procĂ©dure stockĂ©e intĂ©grĂ©e sp_msforeachtable, qui vous permet d'effectuer une requĂȘte sur chaque table de base de donnĂ©es pour gĂ©nĂ©rer un script pour transfĂ©rer des donnĂ©es de l'ancienne base de donnĂ©es vers la nouvelle via une requĂȘte du formulaire

 INSERT INTO ? SELECT * FROM ? 

Au lieu d'un point d'interrogation, sp_msforeachtable remplace le nom de chaque table et exĂ©cute la requĂȘte plusieurs fois (une fois pour chaque table).

Ici, je suis tombé sur le plus grand nombre de rùteaux.

a) Le problÚme numéro un est que pour les tables avec des champs IDENTITY, vous devez appeler:

 SET IDENTITY_INSERT ON; --INSERT INTO ... ( ); SET IDENTITY_INSERT OFF; 

b) Le problÚme numéro deux est que vous ne pouvez pas effectuer cet appel sur des tables qui n'ont pas de champs IDENTITY, vous devez donc déterminer dynamiquement si la table a une colonne IDENITY ou non.

Cela peut ĂȘtre fait avec cette requĂȘte:

 SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE (TABLE_NAME='SomeTable') AND (COLUMNPROPERTY(object_id('dbo.SomeTable'), COLUMN_NAME, 'IsIdentity') = 1) 

c) Le problÚme numéro trois est que, en fin de compte, en mode IDENITY_INSERT ON, vous ne pouvez pas

 INSERT INTO ... SELECT * FROM ... 

, mais vous devez répertorier des champs spécifiques.

Vous pouvez rĂ©pertorier les champs de table dans une ligne avec cette requĂȘte:

 SELECT SUBSTRING( (SELECT ', ' + QUOTENAME(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'SomeTable' ORDER BY ORDINAL_POSITION FOR XML path('')), 3, 200000); 

4) Nous générons un script d'insertion pour toutes les tables:

Procédure de génération de script
 EXEC sp_msforeachtable N' DECLARE @command varchar(MAX); DECLARE @name varchar(200); SET @name=''?''; SET @name = SUBSTRING(@name, 8, LEN(@name)-8); SET @command = ''''; SELECT @command= SUBSTRING( (SELECT '', '' + QUOTENAME(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '''' + @name + '''' ORDER BY ORDINAL_POSITION FOR XML path('''')), 3, 200000); SET @command = ''INSERT INTO ''+ @name +'' (''+ @command + '') SELECT '' + @command + '' FROM '' + ''LinkedServerAlias.SourceDatabase.'' + ''?''; SET @command= ''IF EXISTS (select * from INFORMATION_SCHEMA.COLUMNS where (TABLE_NAME='''''' + @Name + '''''') AND (COLUMNPROPERTY(object_id(''''dbo.''+@Name+''''''), COLUMN_NAME, ''''IsIdentity'''') = 1)) SET IDENTITY_INSERT '' + @name + '' ON; '' +@command; SET @command=@command+'';'' + ''IF EXISTS (select * from INFORMATION_SCHEMA.COLUMNS where (TABLE_NAME='''''' + @Name + '''''') AND (COLUMNPROPERTY(object_id(''''dbo.''+@Name+''''''), COLUMN_NAME, ''''IsIdentity'''') = 1)) SET IDENTITY_INSERT '' + @name + '' OFF;''; PRINT (@command); --EXEC(@command); //  ,    ,       ' 


5) Nous exécutons le script de transfert de données généré

6) Nous exécutons un script pour créer toutes les contraintes de clé étrangÚre (maintenant c'est déjà possible).

7) C'est fait! Vous avez transféré la base de données du nouveau serveur SQL vers l'ancien, bien que cela ait été considéré comme impossible. De plus, le transfert n'est effectué qu'une fois et demi plus lentement que le taux de transfert de données sur le réseau, c'est-à-dire assez vite.

8) Nous nettoyons aprĂšs nous-mĂȘmes (nous dĂ©connectons le serveur liĂ©):

 EXEC sp_droplinkedsrvlogin 'LinkedServerUser', null; sp_dropserver 'LinkedServerAlias'; 

Limitations de la méthode.

1) En utilisant une méthode similaire, il ne sera pas possible de transférer des tables contenant des colonnes de type XML.
Il existe certainement de nombreuses autres restrictions, comme la base de données que j'ai transférée de cette maniÚre n'utilisait pas beaucoup des fonctionnalités du serveur SQL. Vous pouvez écrire sur les restrictions dans les commentaires, et j'y ajouterai un article.

Merci de votre attention! J'espĂšre que cela aide quelqu'un.

Source: https://habr.com/ru/post/fr421189/


All Articles