در چند سال گذشته، دو بار با پروژه‌هایی روبه‌رو شدم که صاحب سایت می‌گفت هیچ چیزی را عوض نکرده، اما سایتشان خودبه‌خود کند شده. در هر دو مورد، بعد از بررسی، مقصر نه قالب بود و نه افزونه‌ها: دیتابیس بود. در مورد اول، جدول wp_options با بیش از ۳۰ هزار ردیف داده اضافی، TTFB (Time To First Byte) را بالا برده بود. در مورد دوم، ردیف‌های یتیم از افزونه‌های حذف‌شده، کوئری‌های سنگین ایجاد می‌کرد. تجربه‌ام می‌گوید بهینه‌سازی دیتابیس وردپرس، یکی از آن موضوعاتی است که تا وقتی به مشکل نخورید، جدی گرفته نمی‌شود؛ اما دقیقاً همان چیزی است که سایت‌های تازه‌کار را در سال دوم، به کندی مزمن دچار می‌کند.

بهینه‌سازی دیتابیس وردپرس دقیقاً چیست؟

وردپرس در ساختار درونی خود، تمام محتوای سایت (نوشته‌ها، برگه‌ها، تنظیمات، کاربران، دیدگاه‌ها) را در یک دیتابیس MySQL یا MariaDB ذخیره می‌کند. با هر نوشته جدید، هر افزونه نصب‌شده، هر بازدید ثبت‌شده و هر تنظیم ذخیره‌شده، داده‌ای به این دیتابیس اضافه می‌شود. برخی از این داده‌ها مفیدند و برخی اضافه؛ بهینه‌سازی دیتابیس یعنی حذف داده‌های اضافه، مرتب‌سازی ساختار جداول، و کاهش فشار روی کوئری‌ها.

تفاوت بهینه‌سازی دیتابیس با کارهایی مثل کش کردن یا بهینه‌سازی تصویر، در این است که اثرش روی TTFB مستقیم است. اگر با مفهوم TTFB آشنا نیستید، تأثیر TTFB بر سرعت بارگذاری پیش‌نیاز این بحث است. همچنین اگر رابطه کلی دیتابیس با سرعت را نمی‌دانید، تأثیر دیتابیس بر سرعت سایت را بخوانید؛ همان چارچوب، مبنای این نوشته است.

دیتابیس، قلب نامرئی سایت وردپرسی است؛ تا وقتی سالم است، دیده نمی‌شود؛ وقتی سنگین شد، همه چیز از کار می‌افتد.

چرا دیتابیس وردپرس، خودبه‌خود سنگین می‌شود؟

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

  • رول‌بک‌ها (post revisions): هر بار که یک نوشته را ذخیره می‌کنید، وردپرس یک نسخه قبلی را نگه می‌دارد. برای پروژه‌های چندساله، این حجم به‌سرعت بالا می‌رود.
  • ترنزینت‌ها (transients): داده‌های موقتی که باید خودکار پاک شوند، اما اگر افزونه‌ای از بین رفته باشد، ترنزینت‌های یتیم می‌مانند.
  • جدول wp_options: هر افزونه‌ای که نصب و حذف می‌کنید، ردیف‌های تنظیماتش را در این جدول باقی می‌گذارد. همان جدول اول داستان من بود.
  • ردیف‌های یتیم (orphaned rows): داده‌هایی که به نوشته یا برگه‌ای که دیگر وجود ندارد، ارجاع دارند.

در تجربه من، بعد از دو سال کار عادی روی یک سایت متوسط، دیتابیس به‌راحتی از ۲۰ مگابایت به ۲۰۰ مگابایت رشد می‌کند، و بخش بزرگی از این رشد، داده‌هایی است که هرگز به کاربر نمایش داده نمی‌شوند. اگر روی هاست اشتراکی کار می‌کنید، این حجم روی TTFB محسوس می‌شود؛ چون هاست‌های اشتراکی معمولاً سقف محدودی برای ظرفیت دیتابیس دارند و روی همان مرز، کوئری‌ها کندتر اجرا می‌شوند.

نشانه‌های نیاز به بهینه‌سازی

پیش از هر اقدام، این نشانه‌ها را در سایت خود بررسی کنید؛ اگر بیش از دو مورد را دیدید، دیتابیس شما به بهینه‌سازی نیاز دارد:

  • پیشخوان وردپرس کند شده، ولی front-end سریع است. این الگو در تجربه من، شایع‌ترین نشانه دیتابیس سنگین است.
  • حجم فایل دیتابیس (در phpMyAdmin یا پنل هاست) نسبت به محتوای سایت بزرگ‌تر از حد انتظار است.
  • افزودن یا ویرایش نوشته طول می‌کشد یا خطای timeout می‌دهد.
  • افزونه‌های بکاپ، هنگام فشرده‌سازی دیتابیس کند می‌شوند یا ناقص عمل می‌کنند.
  • در پنل هاست، مصرف I/O دیسک بالا رفته، بدون آنکه ترافیک سایت افزایش یافته باشد.

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

پاک‌سازی: چه چیزی را باید حذف کرد؟

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

  1. پیش‌نویس‌های خودکار (auto-drafts) و نوشته‌های سطل زباله.
  2. رول‌بک‌های قدیمی نوشته‌ها، به‌جز چند نسخه آخر.
  3. ترنزینت‌های منقضی‌شده و ردیف‌های یتیم در متادیتا.

جدول wp_options و داده‌های اضافی

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

  • ردیف‌های مربوط به افزونه‌های حذف‌شده: اگر افزونه‌ای را حذف کرده‌اید و ردیف‌های آن هنوز در wp_options است، می‌توانید با احتیاط حذف کنید. ولی مطمئن شوید که افزونه واقعاً حذف شده و بازنمی‌گردد.
  • ترنزینت‌های سرگردان: داده‌های موقتی که تاریخ انقضایشان گذشته و دیگر استفاده نمی‌شوند.
  • داده‌های تجمیعی: برخی افزونه‌ها مثل آمارگیر یا اسلایدر، داده‌های خود را در همین جدول انباشته می‌کنند.

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

SELECT option_name, LENGTH(option_value) AS size
FROM wp_options
ORDER BY size DESC
LIMIT 20;

این کوئری، ۲۰ ردیف با بزرگ‌ترین مقدار را نشان می‌دهد. در تجربه من، چند ردیف با نام‌های مشابه (مثل _transient_* یا *_cache) معمولاً بخش بزرگی از حجم را می‌سازند.

رول‌بک‌ها و پیش‌نویس‌های یتیم

وردپرس به‌طور پیش‌فرض، هر بار ذخیره نوشته، یک نسخه رول‌بک می‌سازد. برای سایت‌های با تعداد زیاد ویرایشگر، این ویژگی می‌تواند به‌سرعت جدول wp_posts را پر کند. در تجربه من، تنظیم منطقی، محدود کردن رول‌بک‌ها به ۵ نسخه در فایل wp-config.php است:

define('WP_POST_REVISIONS', 5);

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

DELETE FROM wp_posts
WHERE post_type = 'revision';

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

ترنزینت‌ها: کش دیتابیس در دیتابیس

ترنزینت‌ها (transients)، داده‌های موقتی هستند که وردپرس و افزونه‌ها برای کش کردن نتایج گران، در جدول wp_options ذخیره می‌کنند. این مکانیزم، در تئوری خوب کار می‌کند، اما در تجربه من با دو مشکل روبه‌رو می‌شود:

  1. افزونه‌هایی که ترنزینت ایجاد می‌کنند، در حذف خودکار آن‌ها کوتاهی می‌کنند و ترنزینت‌های منقضی، در جدول باقی می‌مانند.
  2. اگر افزونه‌ای حذف شود، ترنزینت‌های آن به‌عنوان داده یتیم باقی می‌مانند.

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

DELETE a, b FROM wp_options a, wp_options b
WHERE a.option_name LIKE '%_transient_%'
AND a.option_name NOT LIKE '%_transient_timeout_%'
AND b.option_name = CONCAT(
  '_transient_timeout_',
  SUBSTRING(a.option_name, CHAR_LENGTH('_transient_') + 1)
)
AND b.option_value < UNIX_TIMESTAMP();

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

بهینه‌سازی جداول با MySQL

پس از پاک‌سازی، جداول دیتابیس دارای فضای خالی و تکه‌تکه (fragmented) هستند. بهینه‌سازی جداول، این فضا را آزاد و ساختار داخلی را مرتب می‌کند:

OPTIMIZE TABLE wp_posts;
OPTIMIZE TABLE wp_postmeta;
OPTIMIZE TABLE wp_options;

این دستور برای هر جدول جداگانه اجرا می‌شود. اگر تعداد جداول زیاد است، می‌توانید از یک اسکریپت PHP برای اجرای خودکار روی همه استفاده کنید. در تجربه من، بهینه‌سازی جداول بعد از پاک‌سازی، معمولاً بین ۱۰ تا ۳۰ درصد کاهش حجم می‌آورد. جزئیات بیشتر درباره MySQL و بهینه‌سازی کوئری‌ها در بهینه‌سازی جداول MySQL برای سرعت آمده است.

بهینه‌سازی دیتابیس، نه یک جادوی یک‌باره است و نه یک روتین ماهانه؛ چیزی بین این دو، یک عادت فصلی است.

ایندکس و کوئری‌های سنگین

حتی دیتابیس تمیز، می‌تواند با کوئری‌های بدون ایندکس، کند شود. دو کار در این سطح:

  1. شناسایی کوئری‌های کند: فعال‌سازی slow query log در MySQL، کوئری‌هایی که بیش از حد مشخصی طول می‌کشند (مثلاً بیش از ۲ ثانیه) را ثبت می‌کند. در تجربه من، اکثر کوئری‌های کند، از افزونه‌های بدون بهینه‌سازی می‌آید.
  2. ایندکس‌گذاری هدفمند: برای جدول‌های پرترافیک مثل wp_postmeta یا wp_options، افزودن ایندکس روی ستون‌های meta_key یا option_name می‌تواند تفاوت محسوسی بسازد. ولی ایندکس‌گذاری بی‌دقت، حجم جدول را بزرگ‌تر و نوشتن را کندتر می‌کند.

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

ابزارهای بهینه‌سازی و افزونه‌ها

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

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

پاک‌سازی ایمن: قبل، حین و بعد

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

  1. قبل از پاک‌سازی: بکاپ کامل از فایل‌ها و دیتابیس. اگر می‌توانید، سایت را در محیط استجینگ بازسازی کنید و پاک‌سازی را آنجا آزمایش کنید. مسیر استجینگ در راه‌اندازی سایت وردپرسی آمده است.
  2. حین پاک‌سازی: یک‌باره همه کارها را انجام ندهید. ابتدا رول‌بک‌ها، سپس ترنزینت‌ها، سپس ردیف‌های یتیم. بین هر مرحله، سایت را باز کنید و مطمئن شوید همه چیز کار می‌کند.
  3. بعد از پاک‌سازی: به مدت یک هفته، سرعت TTFB و رفتار پیشخوان را پایش کنید. اگر چیزی خراب شد، با بکاپ برگردانید. همچنین مصرف منابع هاست را در پنل بررسی کنید؛ چون پاک‌سازی دیتابیس معمولاً روی مصرف I/O اثر مثبت می‌گذارد. راهنمای کامل در کاهش مصرف منابع هاست آمده است.

جدول مرجع

داده اضافهمحل ذخیرهروش پاک‌سازیریسک
رول‌بک‌های قدیمیwp_postsافزونه یا کوئری DELETEکم
پیش‌نویس‌های خودکارwp_postsافزونهکم
ترنزینت‌های منقضیwp_optionsکوئری DELETE با شرط تاریخمتوسط
ردیف‌های یتیم متادیتاwp_postmetaافزونهمتوسط
ردیف‌های افزونه‌های حذف‌شدهwp_optionsشناسایی دستی + کوئریبالا
دیدگاه‌های اسپمwp_commentsافزونه ضد اسپمکم
فضای خالی جداولهمه جداولOPTIMIZE TABLEکم

پرسش‌های کوتاه

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

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

آیا باید از افزونه بهینه‌سازی استفاده کنم یا کوئری خام؟ اگر تازه‌کار هستید، حتماً افزونه. اگر توسعه‌دهنده باتجربه هستید، ترکیبی از افزونه (برای پاک‌سازی معمول) و کوئری خام (برای موارد خاص) بهترین نتیجه را می‌دهد.

آیا بهینه‌سازی دیتابیس روی رتبه سئو اثر دارد؟ مستقیم نه، اما با کاهش TTFB، تجربه کاربر و Core Web Vitals بهتر می‌شود که اثر غیرمستقیم دارد. مبنای این رابطه در تأثیر سرعت سایت بر سئو آمده است.

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

از نگاه معماری داده

برای توسعه‌دهندگان و مدیران فنی که با پروژه‌های چندساله کار می‌کنند، بهینه‌سازی دیتابیس را باید بخشی از «مدیریت چرخه عمر داده» دید، نه یک کار جانبی. سه اصل معماری که در تجربه‌ام اثر مستقیم داشته‌اند. اول، طراحی برای پاک‌سازی: هر افزونه یا کد سفارشی که روی سایت اضافه می‌شود، باید یک مسیر خروج مشخص برای داده‌های خود داشته باشد. افزونه‌ای که هنگام حذف، جداول و ردیف‌های خود را پاک نمی‌کند، در واقع یک بدهیِ فنی انباشته می‌سازد. دوم، تفکیک داده عملیاتی از داده تحلیلی: جداول ووکامرس و متادیتای محتوایی، داده عملیاتیِ سایت هستند و باید سبک نگه داشته شوند. اما داده‌های تحلیلی (لاگ بازدید، رفتار کاربر)، بهتر است در جدول‌های جداگانه یا حتی سیستم جداگانه (مثل یک warehouse یا ابزار تحلیل بیرونی) نگهداری شوند تا انباشت آن‌ها روی سرعت سایت اثر نگذارد. سوم، پایش ترند نه عدد: به‌جای اینکه فقط اندازه فعلی دیتابیس را نگاه کنید، روند رشد آن را در بازه‌های سه ماهه ثبت کنید. تجربه‌ام می‌گوید در پروژه‌هایی که این پایش انجام شده، مداخله در نقطه‌ای اتفاق افتاده که دیتابیس از ۱۰۰ مگابایت به ۱۵۰ مگابایت می‌رفت؛ در پروژه‌هایی که ندیده شده، اولین مداخله در نقطۀ بحران بوده که هزینه‌اش چند برابر شده. این سه اصل، بهینه‌سازی دیتابیس را از یک کار واکنشی به یک عادت معماری تبدیل می‌کند.

سخن آخر

بهینه‌سازی دیتابیس وردپرس، یکی از کم‌سروصداترین اقدامات نگهداری سایت است؛ چون اثرش در بازه‌های کوتاه محسوس نیست و در بازه‌های بلند، تعیین‌کننده است. تجربه‌ام می‌گوید سه اقدام اول بیشترین بازده را دارند: پاک‌سازی رول‌بک‌های قدیمی، حذف ترنزینت‌های منقضی، و بهینه‌سازی جداول با MySQL. اگر امروز فقط یک کار بکنید، یک بکاپ کامل بگیرید و سپس با یک افزونه معتبر، رول‌بک‌های قدیمی را پاک کنید؛ این ساده‌ترین گام، در سایت‌های چندساله معمولاً بین ۳۰ تا ۵۰ درصد کاهش حجم می‌آورد. باقی مسیر، با تکرار دوره‌ای همان روتین ساخته می‌شود. اگر تجربه‌ای از بهینه‌سازی دیتابیس در پروژه‌ای دارید که در منابع فارسی کمتر گفته شده (مثلاً یک کوئری خاص یا پیکربندی MySQL که تفاوت محسوسی ساخت)، در دیدگاه‌ها بنویسید؛ همان تجربه‌ها، تصویر این بحث را کامل‌تر می‌کنند. 🗄️