ترحيل قاعدة بيانات إلى إصدار أقدم من MS SQL Server



لديك قاعدة بيانات MS SQL Server التي تحتاج إلى نقلها إلى كمبيوتر فعلي آخر. لقد قمت بالفعل بعمل نسخة احتياطية وتشرع بسعادة في التعافي. ولكن بعد ذلك اتضح أنه على الكمبيوتر حيث تريد نقل قاعدة البيانات ، تم تثبيت إصدار أقدم من MS SQL Server. يؤكد Stack Overflow أن كل شيء سيء. ولكن هل هو كذلك حقا؟


بالطبع ، لا يعد نقل قاعدة البيانات من إصدار أحدث إلى إصدار قديم كلاسيكيًا وليس السيناريو الأكثر صحة. ولكن غالبًا ما يتم إنشاء قواعد البيانات بطريقة تدعم المزيد والمزيد من الإصدارات الجديدة من SQL ، بدءًا ببعض منها ، على سبيل المثال ، 2008 R2 ، لأن التوافق المباشر مع MS SQL أكثر من ممتاز. وعلى سبيل المثال ، قام عميلك بالفعل بتثبيت MS SQL 2016 لنفسه ، ولديك MS SQL 2014 مثبتًا على خادم الاختبار الخاص بك للتطوير. وتريد توسيع قاعدة العملاء الخاصة بك لمعرفة أين يوجد ارتباك في البيانات.

مايكروسوفت تخلت عن المشكلة - يقولون أنهم ليس لديهم توافق عكسي ، وليس هناك تمثال نصفي. لا يمكن استعادة النسخة الاحتياطية التي تم إنشاؤها في الخادم الأحدث إلى الخادم الأقدم. نعم ، لديهم أدوات مثل DTS ونسخ قاعدة البيانات والتصدير والاستيراد وما إلى ذلك. لكنها غير مريحة ومرهقة للغاية بحيث أن النقل العادي لقاعدة بيانات كبيرة مع العديد من الجداول لجعل استخدامها غير مناسب بشكل خاص. على أي حال ، أنا شخصياً لم أنجح.

نعم ، يمكنك إنشاء سكربتات SQL لقاعدة البيانات بأكملها ، بما في ذلك البيانات. ولكن تخيل ، لديك مجموعة من حقول النقطة مع البيانات الضخمة في قاعدة البيانات ، وبشكل عام حجم قاعدة البيانات بأكملها هو 500+ GB. تخيل كم سيستغرق هذا البرنامج النصي ، وكم من الوقت سيتم إنشاؤه وتنفيذه.

لذا ، فإن المهمة هي إعادة إنشاء قاعدة البيانات (الهيكل والبيانات) بدقة من الإصدار الجديد من خادم MS SQL في الإصدار الأقدم. توصلت إلى حل بسيط إلى حد ما أريد مشاركته. بالطبع ، يحتوي هذا الحل على عدد كبير من القيود ، ولكن لا يزال في رأيي أفضل من DTS والنصوص.

القيد رقم واحد هو أنك تحتاج إلى الوصول عبر MS SQL Management Studio إلى كل من الخوادم - القديمة والجديدة. إذا لم يكن ذلك ممكنًا ، فيجب أن يكون ذلك ممكنًا على الجهاز من حيث تريد نقل قاعدة البيانات ، وتثبيت إصدار SQL الذي تحتاج فيه إلى نقل قاعدة البيانات من أجل نقل قاعدة البيانات أولاً إلى هذا الإصدار محليًا ، ثم سحبها من خلال النسخ الاحتياطي أو مباشرة من خلال * df ملفات قاعدة البيانات (عبر فصل / إرفاق) إلى الجهاز الجديد (إصدار SQL Server في هذه الحالة سيتطابق بالفعل).

قيود أخرى هي أنك ستحتاج إلى برنامج نصي لمخطط قاعدة البيانات (جميع الكائنات ، بما في ذلك الجداول ، والفهارس ، والثوابت ، والإجراءات المخزنة ، والمشغلات ، وما إلى ذلك) بدون بيانات ، ويجب أن تذهب تعليمات إنشاء قيود المفاتيح الخارجية إلى هذا البرنامج النصي في النهاية ، منفصلة عن البرنامج النصي لإنشاء الجداول نفسها.

سأصف بإيجاز خوارزمية نقل البيانات نفسها. يتم تنفيذ جميع الإجراءات في جلسة إدارة الاستوديو المتصلة بالخادم الذي تريد نقل قاعدة البيانات إليه.

1) على الخادم الجديد ، قم بإنشاء قاعدة بيانات فارغة بنفس الملفات ومجموعات الملفات مثل قاعدة البيانات المحمولة.

2) باستخدام البرنامج النصي لمخطط قاعدة البيانات ، نقوم بإنشاء جميع كائنات قاعدة البيانات (الجداول ، الفهارس ، المشاهدات ، المشغلات ، الإجراءات والوظائف المخزنة) ، ولكن دون إنشاء قيود المفاتيح الأجنبية. لا يمكنك إنشاء FK في هذه المرحلة ، لأنه سوف تتداخل مع إدخال البيانات.

3) نربط قاعدة البيانات التي سننقل منها البيانات كخادم مرتبط ، بحيث يمكنك استخدام قاعدة البيانات القديمة في الاستعلامات إلى قاعدة البيانات الجديدة.

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

4) لأن هياكل قاعدة البيانات هي نفسها ، سنستخدم الإجراء المخزن المدمج sp_msforeachtable ، والذي يسمح لك بإجراء استعلام في كل جدول قاعدة بيانات لإنشاء برنامج نصي لنقل البيانات من قاعدة البيانات القديمة إلى قاعدة البيانات الجديدة من خلال استعلام النموذج

 INSERT INTO ? SELECT * FROM ? 

بدلاً من علامة الاستفهام ، يستبدل sp_msforeachtable اسم كل جدول وينفذ الاستعلام عدة مرات (مرة واحدة لكل جدول).

لقد صادفت هنا أكبر عدد من المكابس.

أ) المشكلة الأولى هي أنه بالنسبة للجداول التي تحتوي على حقول الهوية ، يجب عليك الاتصال:

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

ب) المشكلة الثانية هي أنه لا يمكنك إجراء هذه المكالمة على جداول لا تحتوي على حقول IDENTITY ، لذلك تحتاج إلى تحديد ديناميكي ما إذا كان الجدول يحتوي على عمود IDENITY أم لا.

يمكن القيام بذلك باستخدام هذا الاستعلام:

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

ج) المشكلة الثالثة هي أنه ، كما اتضح ، في وضع IDENITY_INSERT ON ، لا يمكنك فعل ذلك

 INSERT INTO ... SELECT * FROM ... 

، ولكن عليك إدراج حقول محددة.

يمكنك سرد حقول الجدول على التوالي باستخدام هذا الاستعلام:

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

4) نقوم بإنشاء نص إدراج لجميع الجداول:

إجراء إنشاء البرنامج النصي
 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) نقوم بتنفيذ البرنامج النصي لنقل البيانات الذي تم إنشاؤه

6) نقوم بتنفيذ نص برمجي لإنشاء جميع قيود المفاتيح الأجنبية (الآن أصبح ذلك ممكنًا بالفعل).

7) تم! قمت بنقل قاعدة البيانات من خادم SQL الجديد إلى الخادم القديم ، على الرغم من أن ذلك كان يعتبر مستحيلاً. علاوة على ذلك ، يتم النقل مرة واحدة ونصف أبطأ من معدل نقل البيانات عبر الشبكة ، أي سريع جدا.

8) ننظف بعدنا (نقوم بفصل الخادم المرتبط):

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

قيود الطريقة.

1) باستخدام طريقة مماثلة ، لن يكون من الممكن نقل الجداول التي توجد فيها أعمدة من نوع XML.
بالتأكيد هناك العديد من القيود الأخرى ، مثل لم تستخدم قاعدة البيانات التي قمت بنقلها بهذه الطريقة العديد من ميزات خادم SQL. يمكنك الكتابة عن القيود في التعليقات ، وسوف أقوم بإضافة مقال إليها.

شكرا لكم على اهتمامكم! آمل أن يساعد شخص ما.

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


All Articles