بار اول که این خطا را در یک پروژه وردپرسی دیدم، در ساعت شلوغی یک وبلاگ خبری بود؛ هر بار که کاربری صفحه اصلی را باز می‌کرد، دیتابیس با پیام Table './db/wp_options' is marked as crashed and should be repaired پاسخ می‌داد. آن روز ابتدا فکر کردم مسئله از قالب است، ولی وقتی در phpMyAdmin رفتم و جدول را بررسی کردم، فهمیدم فایل جدول در سرور نیمه‌کاره نوشته شده و MySQL در برخورد بعدی، آن را به‌عنوان «شکسته» علامت زده. از آن روز، هر بار این خطا را می‌بینم، پیش از هر چیز سراغ فایل‌های فیزیکی جدول و نوع موتور آن می‌روم، نه سراغ خود کوئری.

خطای Table is marked as crashed دقیقاً چیست؟

خطای Table is marked as crashed and should be repaired یکی از پیام‌های استاندارد MySQL است که زمانی ظاهر می‌شود که فایل فیزیکی جدول در وضعیت ناسالم قرار گرفته و MySQL برای جلوگیری از خرابی بیشتر، دسترسی به آن را محدود کرده است. پیام کامل آن معمولاً به‌شکل زیر است:

ERROR 1194 (HY000): Table 'wp_options' is marked as crashed and should be repaired

این خطا در مستندات رسمی MySQL با کد 1194 و در دسته خطاهای سطح جدول قرار می‌گیرد. مهم‌ترین نکته این است که این خطا با خطاهای سطح کوئری مثل Unknown column یا Column count تفاوت بنیادی دارد. در آن خطاها، کوئری مسئله دارد؛ در این خطا، خود فایل جدول در وضعیت ناسالم است و حتی یک کوئری ساده SELECT * FROM table LIMIT 1 هم خطا می‌دهد. اگر با خانواده خطاهای MySQL آشنایی کامل ندارید، پیشنهاد می‌کنم ابتدا مرور جامعی روی ساختار آن داشته باشید؛ مقاله «آموزش mysql از صفر» نقطه شروع مناسبی است.

علامت «crashed» توسط MySQL در یک فایل وضعیت ذخیره می‌شود. وقتی سرور MySQL پس از یک خاتمه ناگهانی مجدداً بالا می‌آید، فایل‌های MyISAM را بررسی می‌کند. اگر فایل جدول یا فایل ایندکس آن، از نظر ساختار داخلی ناسالم باشد یا با فایل وضعیت مطابقت نداشته باشد، MySQL جدول را در وضعیت crashed علامت می‌زند و از دسترسی بیشتر به آن جلوگیری می‌کند. این علامت‌گذاری، عامدانه است؛ چون ادامه دسترسی به جدول شکسته می‌تواند به خرابی بیشتر داده منتهی شود.

علامت crashed، یک محافظ است نه یک مجازات؛ MySQL با این علامت، جلوی بدتر شدن وضعیت را می‌گیرد.

نکته مهمی که در تجربه من بیش از همه به آن برخورده‌ام، این است که توسعه‌دهندگان تصور می‌کنند این خطا فقط در جداول MyISAM رخ می‌دهد. این باور در بخش بزرگی از موارد درست است، ولی در بافت‌های خاص مثل نصب‌های قدیمی MySQL، جداول mysql.user و mysql.db که از سیستم MyISAM استفاده می‌کنند هم می‌توانند دچار این وضعیت شوند. برای درک دقیق‌تر تفاوت موتورها در این بافت، مرور «تفاوت innodb و myisam» توصیه می‌شود؛ چون این تفاوت، مسیر تشخیص و درمان را کاملاً تغییر می‌دهد.

چرا MySQL جدول را «شکسته» علامت می‌زند؟

برای این‌که بتوانید این خطا را در ریشه رفع کنید، باید مکانیزم پایین‌دستی آن را بلد باشید. علامت crashed زمانی زده می‌شود که MySQL در بررسی فایل‌های جدول، یکی از چهار وضعیت زیر را تشخیص دهد:

  1. ناسازگاری بین فایل داده و فایل ایندکس: تعداد رکوردهای ثبت‌شده در فایل ایندکس با تعداد واقعی در فایل داده هم‌خوان نیست.
  2. ناقص ماندن نوشتن در دیسک: عملیات نوشتن در حین خاتمه سرور نیمه‌کاره مانده و فایل در وضعیت ناسالم قرار گرفته است.
  3. خرابی سکتورهای دیسک: در بعضی موارد، خرابی در سطح دیسک فیزیکی رخ می‌دهد و MySQL این خرابی را در ساختار جدول تشخیص می‌دهد.
  4. ناسازگاری با پرچم جدول: پرچم‌های داخلی جدول که وضعیت آن را نشان می‌دهند، با وضعیت واقعی هم‌خوان نیستند.

در همه این چهار حالت، MySQL نمی‌تواند با اطمینان بگوید که داده‌ها سالم هستند و به همین دلیل، دسترسی به جدول را قفل می‌کند. این رفتار، به‌ویژه در موتورهای مبتنی بر فایل مثل MyISAM اهمیت دارد؛ چون در این موتورها، MySQL مستقیماً فایل‌های دیسک را مدیریت می‌کند و کنترل کم‌تری روی صحت نوشتن دارد.

در مقابل، موتور InnoDB از سیستم‌های ژورنالینگ استفاده می‌کند که امکان بازگردانی وضعیت سالم را حتی پس از خاتمه ناگهانی سرور فراهم می‌کند. به همین دلیل، جداول InnoDB در عمل کم‌تر به این وضعیت می‌رسند. ولی این موتور هم از این خطا مصون نیست؛ در موارد خاص مثل خرابی سیستم فایل یا خرابی دیسک فیزیکی، جداول InnoDB هم می‌توانند به این وضعیت دچار شوند.

نکته ظریف این است که علامت crashed به‌عنوان یک توصیه، در فایل وضعیت جدول ذخیره می‌شود. یعنی اگر سرور MySQL چند بار پشت سر هم خاتمه یابد و بالا بیاید، این علامت باقی می‌ماند تا زمانی که یک عملیات ترمیم صریح انجام شود. به همین دلیل، در بعضی پرونده‌ها، صرفاً ری‌استارت کردن MySQL کافی نیست و باید دستور REPAIR TABLE اجرا شود. برای درک دقیق‌تر دستورات مدیریتی MySQL، مرور «دستورات پرکاربرد mysql» توصیه می‌شود.

علامت crashed در فایل وضعیت جدول ذخیره می‌شود؛ تا زمانی که صریحاً پاک نشود، باقی می‌ماند.

تفاوت InnoDB و MyISAM در مواجهه با خرابی

یکی از پرتکرارترین سؤالاتی که در جلسات فنی مطرح می‌شود این است: چرا بعضی جداول بیشتر از بقیه دچار این خطا می‌شوند؟ پاسخ در تفاوت بنیادی بین دو موتور اصلی MySQL نهفته است. برای درک این تفاوت، جدول زیر کمک‌کننده است:

ویژگیMyISAMInnoDB
سیستم ژورنالینگندارددارد (redo/undo log)
قابلیت تراکنشندارددارد
قفل جدولدر سطح جدولدر سطح ردیف
خاتمه ناگهانی سروراحتمال خرابی بالابازگردانی خودکار
علامت crashedرایجنادر
ترمیمREPAIR TABLEInnoDB Recovery
پشتیبانی در MySQL 8منسوخپیش‌فرض

نکته کاربردی این است که در MySQL 8، موتور MyISAM به‌عنوان یک موتور منسوخ (deprecated) علامت خورده و تیم MySQL توصیه می‌کند که همه جداول به InnoDB مهاجرت کنند. ولی در پروژه‌های قدیمی وردپرسی که سال‌ها پیش ساخته شده‌اند، هنوز جداول MyISAM وجود دارند و همین جداول، منبع اصلی خطای Table is marked as crashed هستند.

در InnoDB، حتی اگر سرور ناگهانی خاتمه یابد، در زمان بالا آمدن مجدد، MySQL با استفاده از لاگ‌های ژورنال، وضعیت پایدار را بازگردانی می‌کند. این فرآیند به‌طور خودکار انجام می‌شود و به مداخله دستی نیاز ندارد. ولی در MyISAM، هیچ لاگی وجود ندارد و MySQL نمی‌تواند تشخیص دهد که کدام عملیات‌ها به‌درستی تکمیل شده‌اند. به همین دلیل، فایل جدول در وضعیت ناسالم می‌ماند و باید صریحاً ترمیم شود.

در بعضی پروژه‌ها، به‌دلیل نیازهای خاص مثل جداول جستجو یا جداول لاگ، هنوز از MyISAM استفاده می‌شود. در این موارد، توصیه من این است که در کنار جدول، یک فرآیند پشتیبان‌گیری منظم داشته باشید تا در صورت خرابی، داده قابل بازیابی باشد. برای مرور دقیق‌تر استراتژی‌های پشتیبان‌گیری در بافت پروژه‌های واقعی، مرور «پشتیبان گیری از mysql» توصیه می‌شود.

در موتور MyISAM، پشتیبان‌گیری منظم، بیمه‌نامه جدول است؛ در InnoDB، همان بیمه‌نامه را سیستم ژورنالینگ به‌طور خودکار فراهم می‌کند.

هشت سناریوی واقعی که جدول را می‌شکند

در پرونده‌هایی که به من رسیده، تعداد الگوهایی که به این خطا منتهی می‌شوند بیشتر از آن‌چه انتظار می‌رود است. هشت سناریوی زیر، تقریباً همه پرونده‌های عملی را پوشش می‌دهند.

سناریو اول: خاتمه ناگهانی سرور

شایع‌ترین حالت. وقتی سرور به‌دلیل قطع برق، خطای سیستم‌عامل یا ری‌استارت اجباری خاتمه می‌یابد، عملیات نوشتن در حین انجام، نیمه‌کاره می‌ماند و جدول شکسته می‌شود. راه‌حل، ترمیم با REPAIR TABLE است.

سناریو دوم: پر شدن فضای دیسک

در هنگام نوشتن داده، اگر فضای دیسک تمام شود، فایل جدول نیمه‌کاره نوشته می‌شود. در این حالت، بعد از آزاد شدن فضا، جدول همچنان در وضعیت ناسالم باقی می‌ماند. راه‌حل، ترمیم و پایش منظم فضای دیسک است.

سناریو سوم: خرابی سخت‌افزار

خرابی سکتورهای هارد دیسک یا خرابی SSD می‌تواند به خرابی فایل‌های جدول منتهی شود. در این حالت، علاوه بر ترمیم جدول، باید سلامت سخت‌افزار هم بررسی شود.

سناریو چهارم: کشتن اجباری پروسه MySQL

در بعضی سناریوها، برای حل مشکلی دیگر، پروسه MySQL با kill -9 خاتمه می‌یابد. این نوع خاتمه، اجازه نمی‌دهد MySQL فایل‌های باز را به‌درستی ببندد و در نتیجه، جدول‌های MyISAM شکسته می‌شوند. راه‌حل، استفاده از mysqladmin shutdown یا systemctl stop mysql به‌جای kill اجباری است.

سناریو پنجم: عملیات سنگین همزمان

در شرایطی که بار زیاد روی سرور است، ممکن است MySQL نتواند به موقع یک فایل را ببندد و در نتیجه، جدول شکسته شود. راه‌حل، توزیع بار و افزایش منابع سرور است.

سناریو ششم: عملیات به‌روزرسانی سرور در حین ترافیک

اگر سرور MySQL در حین ترافیک بالا به‌روزرسانی شود، عملیات‌های درحال‌انجام در میانه راه قطع می‌شوند و جدول شکسته می‌شود. راه‌حل، به‌روزرسانی در ساعات کم‌ترافیک و با هماهنگی دقیق است.

سناریو هفتم: کپی نادرست فایل‌ها

در بعضی پروژه‌ها، به‌جای استفاده از ابزارهای استاندارد مثل mysqldump، فایل‌های فیزیکی جدول کپی می‌شوند. این نوع کپی، مخصوصاً اگر در حین نوشتن انجام شود، منبع خطا است. راه‌حل استاندارد، استفاده از mysqldump یا ابزارهای پشتیبان‌گیری معتبر است.

سناریو هشتم: ویروس یا بدافزار در سرور

در بعضی موارد نادر، بدافزار روی سرور می‌تواند فایل‌های MySQL را تخریب کند. این سناریو در کنار خطای شکستگی، معمولاً نشانه‌های دیگری هم دارد مثل رفتار غیرعادی سرور یا فایل‌های ناشناخته در مسیر داده. راه‌حل، بررسی امنیتی کامل سرور و بازگردانی از پشتیبان سالم است. در هر هشت سناریو، یک نکته مشترک وجود دارد: نوشتن روی فایل جدول در حین یک وضعیت ناسالم، به شکستگی منتهی شده است. برای مرور دقیق‌تر مدیریت تراکنش‌ها و نوشتن ایمن، مرور «تراکنش ها در mysql» توصیه می‌شود.

در همه هشت سناریو، یک نکته مشترک وجود دارد: نوشتن روی فایل جدول در حین یک وضعیت ناسالم.

دام اختصاصی وردپرس و ووکامرس

در تجربه من، بخش بزرگی از پرونده‌های Table is marked as crashed مربوط به پروژه‌های وردپرسی و ووکامرسی است. دلیلش روشن است: این سیستم‌ها در نسخه‌های قدیمی، از موتور MyISAM برای بعضی جداول کلیدی مثل wp_options و wp_postmeta استفاده می‌کردند.

ریشه تاریخی در وردپرس

وردپرس تا نسخه ۴.۲، برای جداول خود از موتور MyISAM استفاده می‌کرد. از نسخه ۴.۲ به بعد، این موتور به InnoDB تغییر یافت، ولی این تغییر فقط در نصب‌های جدید اعمال می‌شد. برای نصب‌های قدیمی، تیم وردپرس یک فرآیند ارتقای اختیاری طراحی کرد. اگر این فرآیند در پروژه شما انجام نشده، جداول شما همچنان روی MyISAM هستند و در معرض خطای شکستگی قرار دارند.

بررسی موتور جداول وردپرس

برای بررسی موتور جداول وردپرس، می‌توانید از کوئری زیر استفاده کنید:

SELECT table_name, engine
FROM information_schema.tables
WHERE table_schema = 'your_wp_database'
  AND table_name LIKE 'wp_%';

اگر مقادیر این ستون شامل MyISAM باشد، پروژه شما در معرض خطای شکستگی است.

مهاجرت از MyISAM به InnoDB در وردپرس

برای مهاجرت جداول وردپرس به InnoDB، می‌توانید از دستور زیر استفاده کنید:

ALTER TABLE wp_posts ENGINE = InnoDB;

توصیه من این است که این کار را جدول‌به‌جدول و در ساعات کم‌ترافیک انجام دهید. پیش از هر تغییر، بکاپ کامل دیتابیس ضروری است. برای مرور دقیق‌تر روش‌های پشتیبان‌گیری در بافت وردپرس، مرور «چگونه از سایت وردپرسی بکاپ بگیریم» و «بهترین افزونه‌های پشتیبان‌گیری وردپرس» توصیه می‌شود.

دام ووکامرس

در ووکامرس، جداول سفارشات و محصولات از موتور InnoDB استفاده می‌کنند، ولی جداول کش و لاگ ممکن است روی MyISAM باشند. اگر این جداول شکسته شوند، فرآیند نمایش محصولات یا ثبت سفارش مختل می‌شود. راه‌حل، ترمیم سریع جدول شکسته و سپس مهاجرت به InnoDB است.

چطور ریشه این خطا را در پروژه ایزوله کنیم؟

فرض کنید همین امروز یک خطای Table is marked as crashed در محیط تولید ظاهر شده و می‌خواهید ریشه‌اش را پیدا کنید. روشی که در این نوع پرونده‌ها به کار می‌گیرم، شش گام دارد و هر گام، یک شرط را در ذهن من حذف می‌کند.

گام اول: نگاه دقیق به نام جدول در پیام خطا

اولین کاری که می‌کنم، نگاه به نام جدول مشکل‌دار است. اگر جدول wp_options باشد، مسئله در تنظیمات سایت است و ممکن است دسترسی به پیشخوان وردپرس را هم مختل کند. اگر جدول از یک افزونه خاص باشد، باید ابتدا آن افزونه را غیرفعال کنم و سپس به ترمیم بپردازم.

گام دوم: بررسی موتور جدول

دومین کاری که می‌کنم، بررسی موتور جدول است:

SELECT table_name, engine
FROM information_schema.tables
WHERE table_schema = 'your_database'
  AND table_name = 'your_table';

اگر موتور MyISAM باشد، مسیر ترمیم از طریق REPAIR TABLE یا myisamchk است. اگر InnoDB باشد، مسیر درمان متفاوتی وجود دارد.

گام سوم: بررسی فضای دیسک

سومین کاری که می‌کنم، بررسی فضای دیسک است:

df -h
du -sh /var/lib/mysql/

اگر فضای دیسک پر باشد، قبل از هر ترمیمی باید فضا آزاد شود. اگر جدول شکسته به‌دلیل پر شدن فضا شکسته باشد، ترمیم بدون آزاد کردن فضا نتیجه نمی‌دهد.

گام چهارم: بررسی لاگ خطا MySQL

چهارمین کاری که می‌کنم، بررسی لاگ خطا MySQL است:

tail -n 200 /var/log/mysql/error.log

این لاگ، دلیل دقیق شکستگی را نشان می‌دهد. اگر دلیل قطع برق یا kill اجباری باشد، معمولاً در لاگ ثبت شده است.

گام پنجم: بررسی سلامت سخت‌افزار

پنجمین کاری که می‌کنم، بررسی سلامت دیسک است:

smartctl -a /dev/sda

اگر خرابی سکتورهای دیسک گزارش شود، ترمیم جدول فقط راه‌حل موقت است و باید به فکر جایگزینی سخت‌افزار باشید.

گام ششم: بررسی الگوهای تکرارشونده

ششمین کاری که می‌کنم، بررسی الگوهای تکرارشونده است. اگر یک جدول خاص چند بار پشت سر هم شکسته شود، نشانه‌ای از یک مسئله ساختاری در آن جدول است. در این حالت، ترمیم‌های تکراری، فقط زمان می‌برند و باید ریشه ساختاری حل شود. برای مرور دقیق‌تر پایداری جداول در بافت بهینه‌سازی، مرور «بهینه‌سازی جداول MySQL برای سرعت بیشتر» توصیه می‌شود.

ترمیم با REPAIR TABLE و مرزهای آن

بعد از تشخیص، رایج‌ترین راه‌حل، استفاده از دستور REPAIR TABLE است. این دستور، برای جداول MyISAM طراحی شده و امکان ترمیم سریع را از طریق خود MySQL فراهم می‌کند:

REPAIR TABLE wp_options;

پیام موفقیت این دستور به‌شکل زیر است:

+---------------------+--------+----------+----------+
| Table               | Op     | Msg_type | Msg_text |
+---------------------+--------+----------+----------+
| your_db.wp_options  | repair | status   | OK       |
+---------------------+--------+----------+----------+

سه سطح ترمیم در این دستور وجود دارد که با گزینه‌های اضافی مشخص می‌شوند:

سطح اول: REPAIR TABLE ساده

در این سطح، MySQL سعی می‌کند ناسازگاری‌های سبک را رفع کند. این سطح در اکثر موارد کافی است و سرعت بالایی دارد.

سطح دوم: REPAIR TABLE با QUICK

این گزینه، فقط فایل ایندکس را ترمیم می‌کند و به فایل داده کاری ندارد. برای جداول بزرگ، این گزینه سریع‌تر است:

REPAIR TABLE wp_options QUICK;

سطح سوم: REPAIR TABLE با EXTENDED

این گزینه، ترمیم عمیق‌تری را انجام می‌دهد و ممکن است زمان بیشتری بگیرد. ولی در بعضی پرونده‌ها، این تنها راه نجات جدول است:

REPAIR TABLE wp_options EXTENDED;

نکته مهمی که در تجربه من بیش از همه به آن برخورده‌ام این است که REPAIR TABLE در همه موتورها کار نمی‌کند. در InnoDB، این دستور پیام خطا می‌دهد و برای ترمیم آن باید از ابزارهای دیگری مثل innodb_force_recovery استفاده کرد. توصیه من این است که قبل از ترمیم، موتور جدول را بررسی کنید تا از روش درست مطمئن شوید.

یک نکته ظریف دیگر این است که REPAIR TABLE در بعضی سناریوها ممکن است داده‌های ناسالم را حذف کند. اگر جدول شامل داده‌های حیاتی است، همیشه قبل از ترمیم، یک نسخه پشتیبان از فایل‌های فیزیکی جدول بگیرید. برای مرور دقیق‌تر دستورات مدیریتی MySQL، مرور «دستورات پرکاربرد mysql» توصیه می‌شود.

ترمیم با myisamchk در سطح فایل

در بعضی سناریوها، ترمیم از طریق REPAIR TABLE کافی نیست یا اصلاً امکان‌پذیر نیست. در این موارد، ابزار myisamchk در سطح فایل عمل می‌کند و کنترل بیشتری به شما می‌دهد. این ابزار، از خط فرمان سیستم‌عامل اجرا می‌شود و نیاز به دسترسی مستقیم به فایل‌های MySQL دارد.

گام اول: خاموش کردن MySQL

پیش از هر اقدامی، باید MySQL را به‌طور کامل خاموش کنید:

sudo systemctl stop mysql

اگر MySQL در حال اجرا باشد، myisamchk نمی‌تواند به‌طور ایمن روی فایل‌ها کار کند و ممکن است به خرابی بیشتر منتهی شود.

گام دوم: بررسی جدول

پیش از ترمیم، وضعیت جدول را با گزینه check بررسی کنید:

myisamchk -c /var/lib/mysql/your_db/wp_options.MYI

این دستور، وضعیت فایل ایندکس را بررسی می‌کند و اگر خرابی وجود داشته باشد، گزارش می‌دهد.

گام سوم: ترمیم سریع

برای ترمیم سریع، از گزینه recover با سطح ساده استفاده کنید:

myisamchk -r /var/lib/mysql/your_db/wp_options.MYI

گام چهارم: ترمیم عمیق

اگر ترمیم ساده کافی نبود، از گزینه safe-recover استفاده کنید:

myisamchk -o /var/lib/mysql/your_db/wp_options.MYI

گزینه -o ترمیم را با روش قدیمی‌تر ولی امن‌تر انجام می‌دهد و در موارد پیچیده، احتمال موفقیت بالاتری دارد.

گام پنجم: راه‌اندازی مجدد MySQL

بعد از ترمیم، MySQL را مجدداً راه‌اندازی کنید:

sudo systemctl start mysql

سپس جدول را از طریق MySQL بررسی کنید:

CHECK TABLE wp_options;

یک نکته عملی مهم: myisamchk فقط برای جداول MyISAM کار می‌کند و روی جداول InnoDB بی‌اثر است. در جدول‌های بزرگ، این ابزار ممکن است ساعت‌ها طول بکشد و مصرف حافظه بالایی داشته باشد. توصیه من این است که قبل از اجرا، فضای کافی روی دیسک داشته باشید. برای مرور دقیق‌تر دستورات در بافت بهینه‌سازی جداول، مرور «بهینه‌سازی جداول MySQL برای سرعت بیشتر» توصیه می‌شود.

myisamchk ابزار نجات نهایی است، ولی باید با احتیاط و فقط در زمان خاموش بودن MySQL اجرا شود.

الگوهای پیشگیری و بازگردانی امن

بعد از ترمیم، نوبت به پیشگیری است. شش الگوی عملی در پروژه‌ها به کارم آمده که هر کدام، احتمال شکستگی دوباره را به‌شکل چشمگیری کم می‌کند.

الگوی اول: مهاجرت به InnoDB

ساده‌ترین و در بسیاری از پروژه‌ها کافی‌ترین راه‌حل، مهاجرت همه جداول به InnoDB است:

ALTER TABLE wp_options ENGINE = InnoDB;

این تغییر، در بلندمدت احتمال شکستگی را به‌شکل بنیادی کم می‌کند.

الگوی دوم: پشتیبان‌گیری منظم

در همه پروژه‌ها، به‌ویژه آن‌هایی که از MyISAM استفاده می‌کنند، پشتیبان‌گیری منظم ضروری است. توصیه من، استفاده از mysqldump یا ابزارهای مشابه است:

mysqldump -u user -p your_db > backup_$(date +%Y%m%d).sql

الگوی سوم: استفاده از سیستم فایل مقاوم

در سرورهای حساس، استفاده از سیستم فایل‌هایی مثل ZFS یا XFS که از حفاظت در برابر خرابی داده پشتیبانی می‌کنند، توصیه می‌شود.

الگوی چهارم: خاموش کردن صحیح MySQL

برای خاموش کردن MySQL، همیشه از دستورات استاندارد استفاده کنید، نه از kill اجباری:

sudo systemctl stop mysql

الگوی پنجم: پایش منظم جداول

در پروژه‌های بالغ، جداول به‌طور دوره‌ای بررسی می‌شوند:

CHECK TABLE wp_options;

اگر جدولی علامت شکستگی زودهنگام داشت، قبل از خرابی کامل ترمیم می‌شود.

الگوی ششم: استفاده از Replication

در پروژه‌های حساس، استفاده از Replication باعث می‌شود که اگر جدول روی سرور اصلی شکسته شود، از سرور نسخه سالم داشته باشید. این الگو، در بلندمدت، زمان بازگردانی را به‌شکل چشمگیری کم می‌کند. برای مرور دقیق‌تر الگوهای بهینه‌سازی، مرور «پشتیبان گیری از mysql» توصیه می‌شود.

اشتباهات رایجی که این خطا را تشدید می‌کنند

در بررسی پرونده‌های این خطا، هفت اشتباه تکراری دیده‌ام که هر کدام، به‌جای رفع مشکل، آن را پیچیده‌تر می‌کند.

  • ترمیم بدون بکاپ. شایع‌ترین اشتباه. اگر ترمیم ناقص باشد، ممکن است بخشی از داده از دست برود. همیشه پیش از ترمیم، نسخه پشتیبان تهیه کنید.
  • استفاده از REPAIR TABLE روی InnoDB. این دستور روی InnoDB کار نمی‌کند و پیام خطا می‌دهد. برای InnoDB باید از ابزارهای دیگر استفاده کرد.
  • اجرای myisamchk در حال اجرای MySQL. این کار می‌تواند به خرابی بیشتر منتهی شود. همیشه ابتدا MySQL را خاموش کنید.
  • نادیده گرفتن علت اصلی شکستگی. اگر علت اصلی حل نشود، جدول مجدداً شکسته می‌شود. باید پیش از ترمیم، علت را بررسی کنید.
  • استفاده از kill -9 برای خاموش کردن MySQL. این روش، اجازه نمی‌دهد MySQL فایل‌ها را به‌درستی ببندد. همیشه از دستورات استاندارد استفاده کنید.
  • تکرار ترمیم روی جدولی که مرتب شکسته می‌شود. اگر یک جدول چند بار شکسته شود، باید مسئله ساختاری آن بررسی شود، نه اینکه هر بار ترمیم شود.
  • نادیده گرفتن لاگ خطا MySQL. لاگ خطا، دلیل دقیق شکستگی را نشان می‌دهد. اگر این لاگ را بررسی نکنید، علت اصلی حل نمی‌شود.

در کنار این هفت اشتباه، یک هشتمین نکته هم وجود دارد که در تیم‌های بزرگ زیاد دیده‌ام: نداشتن مستندات برای فرآیند ترمیم. وقتی تیم فنی نداند که در صورت شکستگی چه گام‌هایی باید بردارد، هر توسعه‌دهنده ممکن است به سلیقه خود عمل کند و این عدم یک‌دستی، در بلندمدت منبع خطاهای تکراری می‌شود.

ماتریس تست پایداری جداول

چیزی که در پروژه‌های بالغ به‌شکل منظم دیده‌ام، تست‌های اختصاصی برای پایداری جداول است. ماتریسی که در پروژه‌ها استفاده می‌کنم، این شکلی است:

سناریوورودیخروجی مورد انتظار
بررسی سلامت جدول سالمCHECK TABLEOK
بررسی سلامت جدول شکستهCHECK TABLEcorrupt
ترمیم جدول MyISAM با REPAIRREPAIR TABLEOK
ترمیم جدول MyISAM با myisamchkmyisamchk -rOK
ترمیم جدول InnoDB با REPAIRخطا در اجراپیام خطا
خاتمه ناگهانی سرورkill -9احتمال crashed
خاتمه درست سرورsystemctl stopجداول سالم
مهاجرت MyISAM به InnoDBALTER TABLE ... ENGINE = InnoDBموفقیت
پشتیبان‌گیری با mysqldumpترافیک فعالفایل معتبر

هر ردیف از این ماتریس، یک سناریوی واقعی را پوشش می‌دهد. اگر این تست‌ها را در پروژه خود بگذارید، نه‌فقط خطاهای زمان اجرا را زودتر می‌گیرید، بلکه وقتی تیم شما بزرگ‌تر می‌شود، رفتار برنامه در برابر تغییرات، قابل پیش‌بینی می‌ماند.

یک تذکر مهم: در تست‌های پایداری، مطمئن شوید که همه لایه‌ها (موتور جدول، تنظیمات سرور، فرآیند پشتیبان‌گیری) با هم‌خوانی یکسان تست می‌شوند. برای مرور دقیق‌تر این بافت، مرور «آموزش mysql از صفر» توصیه می‌شود.

پرسش‌های پرتکرار درباره Table is marked as crashed

در این بخش، پرسش‌هایی که بیشترین تکرار را در تیم‌های فنی، تیکت‌های پشتیبانی و جلسات بازبینی داشته‌اند، پاسخ می‌دهم. هدف این است که بتوانید به‌سرعت به پاسخ برسید، بدون اینکه لازم باشد کل مقاله را دوباره مرور کنید.

آیا این خطا روی InnoDB هم رخ می‌دهد؟

بله، ولی نادر است. در InnoDB، اگر خرابی سخت‌افزار یا خرابی سیستم فایل رخ دهد، ممکن است جدول به این وضعیت دچار شود. ولی برخلاف MyISAM، ابزار ترمیم متفاوتی دارد و نیازمند فرآیندهای پیچیده‌تری است.

آیا با ری‌استارت کردن MySQL خطا برطرف می‌شود؟

در بعضی موارد بله، ولی معمولاً نه. علامت crashed در فایل وضعیت جدول ذخیره می‌شود و تا زمانی که صریحاً پاک نشود، باقی می‌ماند. راه‌حل قطعی، ترمیم با REPAIR TABLE یا myisamchk است.

آیا امکان از دست رفتن داده در ترمیم وجود دارد؟

بله، در بعضی سناریوها ممکن است بخشی از داده از دست برود. به همین دلیل، همیشه پیش از ترمیم، از فایل‌های فیزیکی جدول نسخه پشتیبان تهیه کنید.

چرا این خطا در وردپرس رخ می‌دهد؟

در نسخه‌های قدیمی وردپرس، جداول از موتور MyISAM استفاده می‌کردند که احتمال شکستگی بالاتری دارد. راه‌حل، مهاجرت به InnoDB است.

آیا می‌توانم جدول را در حالت crashed بخوانم؟

خیر، MySQL دسترسی به جدول را در این وضعیت قفل می‌کند. ابتدا باید ترمیم انجام شود.

چطور بفهمم کدام جدول شکسته است؟

پیام خطا معمولاً نام جدول را نشان می‌دهد. برای بررسی همه جداول، از کوئری زیر استفاده کنید:

CHECK TABLE wp_posts, wp_options, wp_postmeta;

آیا استفاده از mysqlcheck روی همه جداول بی‌خطر است؟

بله، ولی روی جداول بزرگ ممکن است زمان‌بر باشد. توصیه من، اجرای آن در ساعات کم‌ترافیک است:

mysqlcheck -u user -p --all-databases

آیا مهاجرت به InnoDB حتماً لازم است؟

در MySQL 8، موتور MyISAM منسوخ شده و تیم MySQL توصیه به مهاجرت کرده است. در پروژه‌های جدید، استفاده از InnoDB استاندارد است.

آیا در هاست اشتراکی می‌توانم این خطا را برطرف کنم؟

در بعضی هاست‌ها، دسترسی به REPAIR TABLE از طریق phpMyAdmin وجود دارد. اگر دسترسی ندارید، باید با پشتیبانی هاست تماس بگیرید.

آیا این خطا روی MariaDB هم رخ می‌دهد؟

بله. MariaDB نیز از همان مکانیزم MyISAM و InnoDB استفاده می‌کند و همین خطا در آن هم دیده می‌شود.

نگاه معمارانه: پایداری جدول به‌عنوان قرارداد

در پروژه‌های بالغ، پایداری جدول به‌عنوان یک تصمیم طراحی سراسری مدیریت می‌شود، نه به‌عنوان یک تنظیم محلی. سه تصمیم معمارانه که در تیم‌های حرفه‌ای دیده‌ام، این کلاس خطا را از یک خطر پنهان به یک ابزار قابل کنترل تبدیل می‌کند.

لایه اول: استانداردسازی موتور جدول

تیم‌های حرفه‌ای برای همه جداول، یک موتور استاندارد انتخاب می‌کنند. در پروژه‌های جدید، این موتور InnoDB است. با این استاندارد، هیچ‌کس به‌طور تصادفی از MyISAM استفاده نمی‌کند و احتمال شکستگی به‌شکل چشمگیری کم می‌شود.

لایه دوم: پشتیبان‌گیری خودکار و تست‌شده

در پروژه‌های مدرن، به‌جای اتکا به پشتیبان‌گیری دستی، از فرآیندهای خودکار استفاده می‌شود. این فرآیندها، هم به‌طور منظم پشتیبان می‌گیرند و هم بازیابی از پشتیبان را در محیط تست تمرین می‌کنند. برای مرور دقیق‌تر این الگو در بافت وردپرس، مرور «بهترین افزونه‌های پشتیبان‌گیری وردپرس» توصیه می‌شود.

لایه سوم: پایش خودکار و هشدار

در پروژه‌های بالغ، پایداری جداول به‌طور خودکار پایش می‌شود. اگر جدولی علامت شکستگی زودهنگام داشت، هشدار به تیم فنی ارسال می‌شود و ترمیم پیش از خرابی کامل انجام می‌گیرد. این لایه، جلوی بسیاری از خرابی‌های بحرانی را در تولید می‌گیرد.

در تمام این سه لایه، یک اصل مشترک وجود دارد: پایداری جدول نه به‌عنوان یک تنظیم محلی، بلکه به‌عنوان یک قرارداد سراسری دیده می‌شود. همین دیدگاه است که تفاوت بین تیم‌هایی که از این کلاس خطا رنج می‌برند و تیم‌هایی که آن را به‌عنوان یک فرصت طراحی می‌بینند، ایجاد می‌کند.

وقتی پایداری جدول به‌عنوان یک قرارداد سراسری دیده شود، از یک تنظیم محلی به یک تعهد سازمانی تبدیل می‌شود.

یک تصمیم کوچک، یک کلاس خطای ازیادرفته

خطای Table is marked as crashed در نگاه اول یک خطای کوچک به‌نظر می‌رسد، اما در عمل، آینه‌ای است که نشان می‌دهد لایه پایداری داده پروژه شما چقدر صریح و کنترل‌شده است. اگر این خطا در تولید ظاهر می‌شود، به احتمال زیاد جای دیگری از سیستم هم جداولی با موتور غیراستاندارد یا فرآیند پشتیبان‌گیری ناقص وجود دارد. به همین دلیل، توصیه عملی من سه چیز است: اول، همه جداول را به InnoDB مهاجرت دهید تا از مزایای ژورنالینگ بهره‌مند شوید؛ دوم، در مرزهای سیستم، یک لایه پشتیبان‌گیری خودکار و تست‌شده بگذارید؛ سوم، در تست‌های خود ماتریس سناریوهای پایداری جداول را بگنجانید تا رفتار برنامه در برابر خرابی‌های ناگهانی، قابل پیش‌بینی بماند.

اگر خطای مشابهی را در یک پروژه واقعی تجربه کرده‌اید — مخصوصاً جایی که ریشه مشکل از آنچه انتظار داشتید دور بوده — تجربه‌تان را در دیدگاه بنویسید. برای من جالب است بدانم کدام لایه بیشترین زمان را از شما گرفت، و آیا الگویی پیدا کردید که با آنچه در این متن آمده، تفاوت داشت. تجربه‌های واقعی شما، این متن را برای خواننده بعدی دقیق‌تر می‌کند. 🗄️