رفع خطاهای متادیتای ناسازگار(inconsistent metadata error) در SQL Server: راهنمای کامل ترمیم پایگاه داده
گاهی اوقات مشکلات جدی در SQL Server رخ میدهند که میتوانند عملکرد کلی پایگاه داده را مختل کنند. یکی از آزاردهندهترین این مسائل، خطای متادیتای ناسازگار (inconsistent metadata error) است. این خطاها توانایی دارند یک پایگاه داده کامل را از کار بیندازند و دسترسی کاربران را به طور کامل متوقف سازند. در این مقاله، به بررسی چگونگی شناسایی و رفع این خطاهای متادیتایی خواهیم پرداخت و همچنین راهکارهایی برای پیشگیری از بروز آنها ارائه میدهیم.
ریشه خطاهای متادیتای ناسازگار: رکوردهای شبح
اغلب اوقات، این خطاها ناشی از خرابی صفحه (page corruption) در فایلهای پایگاه داده هستند. خرابی صفحه معمولاً به شکل “رکوردهای شبح” (ghost records) در یک صفحه پایگاه داده ظاهر میشود. این به آن معناست که در حالی که SQL Server تصور میکند صفحه خالی است، یک رکورد (یا بخشی از آن) همچنان وجود دارد. این وضعیت میتواند منجر به انواع رفتارهای ناسازگار از سوی موتور پایگاه داده شود و مشکلات زیادی ایجاد کند.
شناسایی مشکل: ابزار قدرتمند DBCC CHECKDB
حال، اگر به وجود مشکلی در پایگاه داده خود مشکوک هستید، چگونه میتوانید آن را شناسایی کنید؟ روش اصلی، اجرای DBCC CHECKDB بر روی پایگاه داده مورد نظر است. DBCC CHECKDB یک ابزار حیاتی است که یکپارچگی فیزیکی و منطقی تمامی اشیاء موجود در پایگاه داده مشخص شده را بررسی میکند. توصیه میشود این دستور به طور منظم بر روی تمام پایگاههای داده کاربران و همچنین پایگاههای داده سیستمی (master، model، msdb، tempdb) اجرا شود. در صورت یافتن هرگونه مشکل، گزارش کاملی از آن ارائه خواهد کرد.
پیش از ادامه، برای نمایش عملی این مشکل، یک پایگاه داده آزمایشی ایجاد میکنم. این پایگاه داده شامل یک جدول و مقداری داده اولیه خواهد بود.
CREATE DATABASE TestDB;
GO
USE TestDB;
GO
CREATE TABLE tblTest (Col1 INT PRIMARY KEY, Col2 VARCHAR(50));
GO
INSERT INTO tblTest VALUES (1, 'Test Data 1');
INSERT INTO tblTest VALUES (2, 'Test Data 2');
INSERT INTO tblTest VALUES (3, 'Test Data 3');
INSERT INTO tblTest VALUES (4, 'Test Data 4');
INSERT INTO tblTest VALUES (5, 'Test Data 5');
GO
این کد پایگاه دادهای به نام TestDB ایجاد میکند و سپس جدولی به نام tblTest با چند سطر داده اولیه در آن میسازد تا بتوانیم سناریوی خرابی را شبیهسازی کنیم.
شبیهسازی خرابی صفحه: ایجاد عمدی خطای متادیتا
اکنون که یک پایگاه داده برای کار داریم، میتوانیم مشکل خرابی صفحه را شبیهسازی کنیم. این کار شامل ویرایش دستی یک صفحه داده در پایگاه داده خواهد بود. هشدار: هرگز این کار را روی یک پایگاه داده عملیاتی (Production Database) یا پایگاه دادهای که برایتان مهم است انجام ندهید. این عملیات میتواند منجر به از دست رفتن دادهها (DATA LOSS) شود.
USE TestDB;
GO
DBCC TRACEON(3604);
DBCC PAGE('TestDB', 1, 142, 3);
GO
در کد بالا، ما محتویات صفحه 142 در فایل 1 از پایگاه داده TestDB را مشاهده میکنیم. سرصفحه صفحه (page header) شامل اطلاعاتی درباره صفحه است، از جمله نوع صفحه. در پایین صفحه، پنج ورودی آرایه اسلات (slot array entries) وجود دارد. این ورودیها به ابتدای هر رکورد در صفحه داده اشاره میکنند. هر رکورد دارای طول 8 بایت است. ما قصد داریم ورودی سوم آرایه اسلات را خراب کنیم، که به این معنی است که رکورد سوم روی صفحه را دچار فساد خواهیم کرد.
DBCC WRITEPAGE('TestDB', 1, 142, 0x000000A0, 2, 0x0000);
GO
با اجرای این دستور، دو بایت از دادهها را در صفحه تغییر دادهایم. ما ورودی سوم آرایه اسلات را به یک آفست (offset) نادرست اشاره دادهایم. این بدان معناست که وقتی SQL Server سعی میکند رکورد سوم را در صفحه بخواند، آفست نادرستی برای دادهها را میخواند. نتیجه این کار، بروز خطای متادیتای ناسازگار خواهد بود.
اجرای DBCC CHECKDB پس از خرابی: مشاهده خطاها
اکنون که صفحه را خراب کردهایم، میتوانیم DBCC CHECKDB را بر روی پایگاه داده TestDB اجرا کنیم. خطایی مشابه موارد زیر مشاهده خواهید کرد:
DBCC CHECKDB ('TestDB') WITH NO_INFOMSGS, ALL_ERRORMSGS;
GO
پس از اجرای دستور فوق، خروجیهای متعددی ظاهر میشود که نشاندهنده خرابی و ناسازگاری متادیتا است. این خطاها شامل موارد زیر هستند:
DBCC results for 'TestDB'.
Msg 8928, Level 16, State 1, Line 1
Object ID 495752312, index ID 1, partition ID 72057594038697984, alloc unit ID 72057594038697984 (type In-row data): Page (1:142) could not be processed. See other errors for details.
Msg 8939, Level 16, State 98, Line 1
Table error: Object ID 495752312, index ID 1, partition ID 72057594038697984, alloc unit ID 72057594038697984 (type In-row data), page (1:142), row 2. Test (offset 0x0) failed. Values are 0x0.
Msg 8976, Level 16, State 1, Line 1
Table error: Object ID 495752312, index ID 1, partition ID 72057594038697984, alloc unit ID 72057594038697984 (type In-row data), page (1:142), row 2. IsClustered is 1 and the record is not a data record.
Msg 8978, Level 16, State 1, Line 1
Table error: Object ID 495752312, index ID 1, partition ID 72057594038697984, alloc unit ID 72057594038697984 (type In-row data), page (1:142), row 2. Offset 0x60 is not a data record.
Msg 8993, Level 16, State 1, Line 1
Table error: Object ID 495752312, index ID 1, partition ID 72057594038697984, alloc unit ID 72057594038697984 (type In-row data). The row is marked as a ghost record, but was not found in the Ghost record version store.
Msg 8956, Level 16, State 1, Line 1
DBCC results for 'tblTest'.
There are 4 rows in 1 pages for object "tblTest".
Msg 8909, Level 16, State 1, Line 1
Table error: Object ID 495752312, index ID 1, partition ID 72057594038697984, alloc unit ID 72057594038697984 (type In-row data). Pages (1:142) and (1:143) are allocated to the same object ID and index ID, but were not processed.
CHECKDB found 0 allocation errors and 7 consistency errors in table 'tblTest' (Object ID 495752312).
CHECKDB found 0 allocation errors and 7 consistency errors in database 'TestDB'.
repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB (TestDB).
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
همانطور که مشاهده میکنید، DBCC CHECKDB خطاهای متعددی را در پایگاه داده TestDB گزارش کرده است. مهمترین بخش این گزارش این است که اشاره میکند: repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB (TestDB). این پیام به وضوح نشان میدهد که برای رفع این خطاها، حداقل سطح ترمیم REPAIR_ALLOW_DATA_LOSS نیاز است که هشداری جدی در مورد احتمال از دست رفتن دادههاست.
رفع مشکل: استفاده از REPAIR_ALLOW_DATA_LOSS (با احتیاط!)
ما اکنون با یک مشکل روبرو هستیم و DBCC CHECKDB راه حل آن را به ما گفته است. باید DBCC CHECKDB را با گزینه REPAIR_ALLOW_DATA_LOSS اجرا کنیم. این دستور تلاش میکند مشکل را رفع کند؛ با این حال، ممکن است منجر به از دست رفتن دادهها شود. به همین دلیل است که داشتن یک نسخه پشتیبان (backup) بهروز از پایگاه داده شما اهمیت فوقالعادهای دارد. اگر نسخه پشتیبان نداشته باشید، ممکن است دادههای مهمی را از دست بدهید.
زمانی که با یک پایگاه داده خراب مواجه هستید، در واقع از قبل با از دست رفتن دادهها دست و پنجه نرم میکنید. در چنین شرایطی، اجرای CHECKDB با REPAIR_ALLOW_DATA_LOSS صفحات خراب را حذف کرده و به شما امکان دسترسی مجدد به پایگاه داده را میدهد. این دستور باید تنها زمانی استفاده شود که هیچ راه دیگری برای بازیابی وجود ندارد و شما آماده پذیرش ریسک از دست دادن بخشی از دادهها هستید.
همچنین میتوانیم برای ترمیم بیشتر، تمام ایندکسهای پایگاه داده را با دستور زیر بازسازی کنیم:
DBCC DBREINDEX(‘tblTest’)
این دستور میتواند به رفع برخی ناسازگاریها که ناشی از خرابی ایندکسها هستند کمک کند.
پس از اتمام کار و بررسی صحت پایگاه داده، میتوانید پایگاه داده آزمایشی را با دستور زیر حذف کنید:
DROP DATABASE TestDB;
GO
این کار به حذف کامل پایگاه داده TestDB از سرور کمک میکند.
خلاصه و بهترین شیوهها برای مدیریت خطاهای متادیتا
در این مقاله، بررسی کردیم که چگونه خطاهای متادیتای ناسازگار (inconsistent metadata errors) میتوانند در SQL Server رخ دهند و چطور میتوان آنها را رفع کرد. دیدیم که این خطاها اغلب به دلیل خرابی صفحه (page corruption) ایجاد میشوند و گاهی اوقات به شکل “رکوردهای شبح” (ghost records) ظاهر میگردند. همچنین، آموختیم که DBCC CHECKDB ابزار اصلی برای شناسایی و ترمیم این خطاهاست، اگرچه ممکن است استفاده از گزینه REPAIR_ALLOW_DATA_LOSS ضروری باشد که میتواند منجر به از دست رفتن دادهها شود.
همواره تاکید میشود که قبل از اقدام به هرگونه عملیات ترمیمی، از وجود یک نسخه پشتیبان (backup) بهروز و کامل از پایگاه داده خود اطمینان حاصل کنید. این کار حیاتیترین گام برای محافظت از دادههای شما در برابر از دست رفتن احتمالی است.