در یکی از پروژه‌های فروشگاهی، سایت با دیتابیس ۳ گیگابایتی کار می‌کرد. صاحب سایت از کندی شدید پیشخوان شکایت داشت. وقتی بررسی کردیم، ۱٫۸ گیگابایت از دیتابیس را ریویژن‌های پست‌ها، ترنزینت‌های منقضی و لاگ‌های افزونه‌های قدیمی تشکیل می‌داد — داده‌ای که هیچ‌کدام برای سایت لازم نبود. بعد از پاک‌سازی مرحله‌ای و بهینه‌سازی، دیتابیس به ۱٫۲ گیگابایت رسید و سرعت پیشخوان به‌طور محسوس بهبود یافت. پاک‌سازی دیتابیس، یکی از پُربازده‌ترین اقدامات در بهینه‌سازی سایت است، اگر امن انجام شود. در این راهنما، پروتکل گام‌به‌گام امن را باز می‌کنم.

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

هشدار پیش از شروع

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

  1. هیچ‌وقت بدون بکاپ کامل شروع نکنید. بکاپ باید شامل فایل و دیتابیس باشد.
  2. پاک‌سازی را روی محیط staging انجام دهید. اگر نتیجه درست بود، روی تولید اعمال کنید.
  3. هیچ‌وقت همه چیز را یک‌جا حذف نکنید. مرحله‌ای پیش بروید و بین مراحل تست کنید.
پاک‌سازی دیتابیس، مثل جراحی است: با دقت و مرحله‌ای انجام می‌شود، نه با یک کوئری حذف گسترده.

ساختار دیتابیس وردپرس

پیش از هر اقدامی، باید ساختار جداول وردپرس را بشناسید. دیتابیس وردپرس، ۱۲ جدول پیش‌فرض دارد:

جدولمحتواحجم معمول
wp_postsپست‌ها، برگه‌ها، ریویژن‌هازیاد
wp_postmetaمتادیتای پست‌هازیاد
wp_optionsتنظیمات سایتمتوسط
wp_usersکاربرانکم
wp_usermetaمتادیتای کاربرانمتوسط
wp_termsدسته‌ها و برچسب‌هاکم
wp_term_taxonomyرابطه دسته‌ها با محتواکم
wp_term_relationshipsرابطه محتوا با دسته‌هامتوسط
wp_termmetaمتادیتای دسته‌هاکم
wp_commentsدیدگاه‌هامتوسط
wp_commentmetaمتادیتای دیدگاه‌هاکم
wp_linksلینک‌های قدیمی (معمولاً خالی)ناچیز

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

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

  1. جداول حیاتی: هرگز مستقیم دست نزنید. مثل wp_posts و wp_users.
  2. جداول قابل‌پاکسازی: داده‌های زائد دارند. مثل wp_postmeta و wp_options.
  3. جداول افزونه‌ها: با افزونه پاک می‌شوند، نه دستی.

چه چیزی امن است و چه چیزی خطرناک؟

پیش از شروع، این جدول را جدی بگیرید:

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

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

گام صفر: بکاپ کامل

بکاپ کامل، پیش‌نیاز غیرقابل‌مذاکره است. سه جزء:

  1. بکاپ دیتابیس: خروجی SQL از کل دیتابیس.
  2. بکاپ فایل‌ها: پوشه wp-content کامل.
  3. بکاپ wp-config.php: جدا از فایل‌ها، چون اطلاعات حساس دارد.
# بکاپ دیتابیس با mysqldump
mysqldump -u username -p --single-transaction \
    --routines --triggers \
    database_name > backup_$(date +%Y%m%d_%H%M).sql

پارامتر --single-transaction باعث می‌شود بکاپ بدون قفل‌کردن جداول گرفته شود. برای سایت‌های فعال، حیاتی است. راهنمای تفصیلی در بکاپ دیتابیس وردپرس و بکاپ وردپرس.

پیش از هر پاک‌سازی، این دو عدد را ثبت کنید:

# اندازه کل دیتابیس
SELECT SUM(ROUND(((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024), 2)) AS 'Size (MB)'
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'database_name';

این عدد، نقطه مرجع شماست. پس از پاک‌سازی، با عدد جدید مقایسه می‌کنید تا اثر کار را بسنجید.

پاک‌سازی ریویژن‌ها

ریویژن (Revision)، نسخه‌های قبلی یک پست که وردپرس برای امکان بازیابی ذخیره می‌کند. در سایت‌های پُرمحتوا، ریویژن‌ها می‌توانند حجم دیتابیس را چند برابر کنند.

بررسی حجم ریویژن‌ها

SELECT COUNT(*) as revisions_count
FROM wp_posts
WHERE post_type = 'revision';

اگر عدد بیش از ۱۰۰۰ است، پاک‌سازی زمانش رسیده.

حذف ریویژن‌های قدیمی (نگه‌داشتن ۵ ریویژن آخر)

DELETE FROM wp_posts
WHERE post_type = 'revision'
  AND ID NOT IN (
    SELECT ID FROM (
        SELECT ID FROM wp_posts p1
        WHERE post_type = 'revision'
          AND post_parent = p1.post_parent
        ORDER BY post_date DESC
        LIMIT 5
    ) AS keep
);

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

SELECT post_parent, COUNT(*) as revisions
FROM wp_posts
WHERE post_type = 'revision'
GROUP BY post_parent
HAVING revisions > 10
ORDER BY revisions DESC;

حذف کامل ریویژن‌ها

اگر مشتری تصمیم گرفته که هیچ ریویژنی نگه ندارد (به‌نظر من توصیه نمی‌شود):

DELETE FROM wp_posts WHERE post_type = 'revision';
DELETE pm FROM wp_postmeta pm
LEFT JOIN wp_posts p ON pm.post_id = p.ID
WHERE p.ID IS NULL;

کوئری دوم، متادیتای ریویژن‌های حذف‌شده را پاک می‌کند.

جلوگیری از تولید ریویژن‌های اضافی

در wp-config.php، تعداد ریویژن‌ها را محدود کنید:

define( 'WP_POST_REVISIONS', 5 );

این خط، حداکثر ۵ ریویژن برای هر پست نگه می‌دارد. مسیر تفصیلی در ریویژن‌ها و کندی دیتابیس.

ریویژن‌ها برای موقعیت‌های اضطراری مفیدند، ولی سایت‌هایی که ۵۰ ریویژن برای هر پست دارند، دیتابیسی دارند که سه برابر لازم است.

پاک‌سازی اسپم و دیدگاه‌های زائد

در سایت‌های پُرترافیک، دیدگاه‌ها می‌توانند حجم قابل‌توجهی اشغال کنند. سه دسته:

دسته اول: اسپم

SELECT COUNT(*) FROM wp_comments WHERE comment_approved = 'spam';

حذف:

DELETE FROM wp_comments WHERE comment_approved = 'spam';

دسته دوم: سطل زباله

DELETE FROM wp_comments WHERE comment_approved = 'trash';

دسته سوم: ترک‌بک و پینگ‌بک

DELETE FROM wp_comments
WHERE comment_type IN ('trackback', 'pingback');

ترک‌بک و پینگ‌بک، در اکثر سایت‌های مدرن کاربردی ندارند و فقط حجم ایجاد می‌کنند.

پاک‌سازی متادیتای دیدگاه‌های حذف‌شده

DELETE cm FROM wp_commentmeta cm
LEFT JOIN wp_comments c ON cm.comment_id = c.comment_ID
WHERE c.comment_ID IS NULL;

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

جلوگیری از انباشت

در بخش تنظیمات → گفتگو، گزینه‌های زیر را فعال کنید:

✓ نویسنده دیدگاه باید نام و ایمیل را وارد کند
✓ دیدگاه‌ها باید دستی تأیید شوند
✓ هر پیوندی در دیدگاه وجود دارد، در انتظار بررسی بماند
✓ سطل زباله دیدگاه‌ها هر روز خالی شود

پاک‌سازی ترنزینت‌ها

ترنزینت (Transient)، داده‌های موقت در وردپرس است که برای کش استفاده می‌شود. مثلاً نتایج API بیرونی، اطلاعات زمان‌بندی‌شده. ترنزینت‌ها تاریخ انقضا دارند و باید بعد از انقضا پاک شوند، ولی در بعضی افزونه‌ها این اتفاق نمی‌افتد.

بررسی ترنزینت‌های منقضی

SELECT COUNT(*) as expired_transients
FROM wp_options
WHERE option_name LIKE '_transient_timeout_%'
  AND option_value < UNIX_TIMESTAMP();

حذف ترنزینت‌های منقضی

DELETE FROM wp_options
WHERE option_name LIKE '_transient_timeout_%'
  AND option_value < UNIX_TIMESTAMP();

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

DELETE t FROM wp_options t
LEFT JOIN wp_options tt
    ON t.option_name = CONCAT( '_transient_', SUBSTRING( tt.option_name, 20 ) )
WHERE t.option_name LIKE '_transient_%'
  AND tt.option_id IS NULL
  AND t.option_name NOT LIKE '_transient_timeout_%';

مسیر تفصیلی در Transient در وردپرس.

توجه به ترنزینت‌های فعال

هرگز ترنزینت‌هایی که هنوز منقضی نشده‌اند را حذف نکنید. مثلاً ترنزینت‌های سئوی Yoast، معمولاً برای مدت ۲۴ ساعت نگه داشته می‌شوند. حذفشان، تولید مجدد را تحریک می‌کند و بار CPU را بالا می‌برد.

پاک‌سازی لاگ‌های افزونه‌ها

افزونه‌های متعددی، لاگ‌های داخلی تولید می‌کنند که اغلب به‌صورت خودکار پاک نمی‌شوند:

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

این لاگ‌ها معمولاً در جداول اختصاصی یا در wp_options ذخیره می‌شوند. برای بررسی:

SHOW TABLES LIKE 'wp_%log%';
SHOW TABLES LIKE 'wp_%_logs';

برای هر جدول، حجم را ببینید:

SELECT TABLE_NAME,
    ROUND(((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024), 2) AS 'Size (MB)'
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'database_name'
  AND TABLE_NAME LIKE '%log%'
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC;

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

DELETE FROM wp_myplugin_logs WHERE created_at < DATE_SUB( NOW(), INTERVAL 90 DAY );

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

پاک‌سازی داده‌های یتیم

داده یتیم (Orphan Data)، اطلاعاتی است که در دیتابیس باقی مانده ولی مرجع اصلی‌اش حذف شده. سه دسته رایج:

دسته اول: متادیتای پست بدون پست

DELETE pm FROM wp_postmeta pm
LEFT JOIN wp_posts p ON pm.post_id = p.ID
WHERE p.ID IS NULL;

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

DELETE um FROM wp_usermeta um
LEFT JOIN wp_users u ON um.user_id = u.ID
WHERE u.ID IS NULL;

دسته سوم: رابطه دسته بدون پست

DELETE tr FROM wp_term_relationships tr
LEFT JOIN wp_posts p ON tr.object_id = p.ID
WHERE p.ID IS NULL;

این سه کوئری، حجم قابل‌توجهی از دیتابیس‌های قدیمی را آزاد می‌کنند. در یکی از پروژه‌ها، حذف داده‌های یتیم تنها، ۲۰۰ مگابایت از دیتابیس آزاد کرد.

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

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

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

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

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

mysqlcheck -u username -p --optimize database_name

یا با یک کوئری که خودش همه جداول را پیدا و بهینه کند:

SET @db = 'database_name';
SELECT CONCAT( 'OPTIMIZE TABLE ', GROUP_CONCAT(TABLE_NAME) )
INTO @sql
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = @db;

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

InnoDB و بهینه‌سازی آنلاین

در MySQL نسخه ۵.۷ به بالا و MariaDB، موتور پیش‌فرض InnoDB است که بهینه‌سازی را به‌صورت آنلاین انجام می‌دهد. یعنی سایت قطع نمی‌شود، ولی روی سرور فشار وارد می‌کند. برای سایت‌های پُربازدید، بهینه‌سازی را در ساعات کم‌ترافیک انجام دهید.

OPTIMIZE TABLE wp_posts;
-- برای InnoDB معادل:
ALTER TABLE wp_posts ENGINE=InnoDB;

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

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

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

افزونه‌هایی مثل WP-Optimize و WP-Sweep، پاک‌سازی دیتابیس را با رابط کاربری ساده انجام می‌دهند. مناسب برای کاربران غیرفنی.

مزایا:

  • رابط کاربری ساده.
  • پیش‌نمایش قبل از پاک‌سازی.
  • گزارش تغییرات.

معایب:

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

مقایسه تفصیلی در بهترین افزونه‌های بهینه‌سازی دیتابیس.

مسیر دوم: WP-CLI

WP-CLI (رابط خط فرمان وردپرس)، قدرتمندترین ابزار. نمونه دستورات:

# حذف ریویژن‌ها
wp post delete $( wp post list --post_type=revision --format=ids ) --force

# پاک‌سازی ترنزینت‌ها
wp transient delete --expired

# بهینه‌سازی جداول
wp db optimize

# پاک‌سازی اسپم‌ها
wp comment delete $( wp comment list --status=spam --format=ids ) --force

مناسب برای مدیران سیستم و توسعه‌دهندگان.

مسیر سوم: دستی با phpMyAdmin

کنترل کامل، ولی ریسک بالا. فقط برای کسانی که با SQL آشنایی دارند.

در پروژه‌های خودم، ترکیبی از سه مسیر استفاده می‌کنم: WP-CLI برای کارهای معمول، دستی برای کارهای خاص، افزونه برای مانیتورینگ دوره‌ای.

انتخاب ابزار، بستگی به مهارت شما دارد. کار با WP-CLI سریع‌تر و دقیق‌تر است، ولی نیازمند دانش خط فرمان است.

اشتباهات رایج در پاک‌سازی

  1. پاک‌سازی بدون بکاپ: بزرگ‌ترین اشتباه. حتی اگر مطمئن هستید، بکاپ بگیرید.
  2. استفاده از افزونه ناشناس: بعضی افزونه‌های پاک‌سازی، خودشان بدافزارند. مسیر تشخیص در دانلود افزونه مطمئن.
  3. حذف همه ریویژن‌ها: ریویژن‌ها برای بازیابی مفیدند. حداقل ۵ تا نگه دارید.
  4. حذف ترنزینت‌های فعال: فقط منقضی‌ها را پاک کنید.
  5. حذف جداول افزونه‌های فعال: پیش از حذف، افزونه را غیرفعال و حذف کنید.
  6. نادیده گرفتن حجم جداول وردپرس: بعضی جدول‌ها مثل wp_options ممکن است حاوی داده‌های حساس باشد.
  7. بهینه‌سازی در ساعات پیک: بهینه‌سازی، منبع مصرف می‌کند. ساعات کم‌ترافیک.
  8. فراموش کردن جدول‌های ووکامرس: در فروشگاه‌ها، جداول wc_* حجم بالایی دارند. پاک‌سازی با احتیاط بیشتری انجام شود.
  9. پاک‌سازی بدون اندازه‌گیری: عدد قبل و بعد را ثبت کنید تا اثر کار را ببینید.
  10. اجرای کوئری‌های سنگین روی سایت زنده: کوئری حذف روی جدول بزرگ، ممکن است سایت را برای دقایقی از کار بیندازد.

خط پایان

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

  1. پاک‌سازی مرحله‌ای: هر مرحله، یک نوع داده زائد را حذف می‌کند.
  2. تست بین مراحل: بعد از هر مرحله، سایت را بررسی کنید.
  3. ثبت عدد: قبل و بعد، اندازه دیتابیس را یادداشت کنید.

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

اگر در پاک‌سازی دیتابیس سایت خود به موقعیتی برخوردید که در این چارچوب نمی‌گنجد — مثلاً یک افزونه خاص با جداول حجیم، یا یک دیتابیس با میلیون‌ها رکورد — در دیدگاه‌ها بنویسید. تجربه‌های واقعی هر پروژه، این راهنما را دقیق‌تر می‌کند. 🧹