WordPress Database Optimization: Hướng Dẫn Dọn Dẹp Database Giảm 60% Thời Gian Query

Nếu bạn đã cài mọi caching plugin trên WordPress mà vẫn thấy site chậm, người gọi đầu tiên bạn nghĩ đến chính là database. Mình đã gặp nhiều website có database lên đến 500MB chỉ với 200 bài viết, và 78% trong đó là “rác” — post revisions, expired transients, orphaned metadata. Bài này mình sẽ hướng dẫn bạn dọn dẹp database WordPress từng bước, từ kiểm tra đến optimize, bằng cả WP-CLI và SQL commands.

Trước khi bắt đầu, mình gợi ý bạn nên đọc qua bài PHP-FPM và OPcache Tuning cho WordPressCloudflare Full Page Cache cho WordPress để có hình tổng thể về performance optimization.

Mục lục Ẩn

Database WordPress Bloat Là Gì Và Sao Phải Dọn Dẹp?

Database bloat là tình trạng database phình to vì dữ liệu không còn sử dụng nhưng vẫn chưa bị xóa. WordPress lưu tất cả — bài viết, revision, comment, settings, transient — vào MySQL/MariaDB. Khi dữ liệu rác tích lũy, mỗi query phải đọc qua nhiều hơn, kết quả là site chậm dần mà bạn không nhận ra.

Theo nghiên cứu từ Patchstack, năm 2025 có 11.334 vulnerability mới trong hệ sinh thái WordPress, tăng 42% so với 2024. Nhưng điều đó không liên quan trực tiếp đến database bloat, nhưng nó cho thấy hầu hết site WordPress đều chạy nhiều plugin, và mỗi plugin để lại dữ liệu rác trong database khi gỡ ra. Đây là nguyên nhân chính gây slow query.

Cấu Trúc Database WordPress Như Thế Nào?

Một cái WordPress cài đặt mặc định tạo ra 12 table trong MySQL. Những table thường gây performance issues nhất là:

  • wp_posts — lưu tất cả content bao gồm posts, pages, revisions, attachments. Table này phình to nhanh nhất vì post revisions.
  • wp_postmeta — metadata cho posts. Hay bị “orphan” khi bạn xóa post nhưng metadata vẫn ở lại.
  • wp_options — settings của toàn bộ site và plugin. Đây là table nguy hiểm nhất vì autoloaded options.
  • wp_comments / wp_commentmeta — phình to vì spam comments dường như không bao giờ tự xóa.

Một điều rất ít người biết: mỗi lần trang web của bạn load, WordPress lấy ALL autoloaded options từ wp_options. Khi dữ liệu này vượt 800KB, site của bạn tự động chậm thêm 100-200ms cho mỗi request. Mình từng gặp site có 5MB autoloaded options — tương đương bắt mỗi visitor tải xuống một bức ảnh high-res chỉ để xem homepage.

Cách Kiểm Tra Database Có Bloat Không?

Bạn cần đánh giá trước khi dọn dẹp. Có 2 cách: dùng WP-CLI (nhanh nhất) hoặc phpMyAdmin. Mình khuyên dùng WP-CLI vì nhanh, an toàn, và không phụ thuộc browser.

Bước 1: Kiểm tra tổng kích thước autoloaded options

Chạy lệnh sau qua WP-CLI:

wp db query "SELECT SUM(CHAR_LENGTH(option_value)) AS total_bytes, COUNT(*) AS total_options FROM wp_options WHERE autoload='yes';"

Nếu total_bytes lớn hơn 1.000.000 (1MB), bạn có vấn đề. Lớn hơn 5MB là critical.

Bước 2: Tìm những option ăn nhiều nhất

wp db query "SELECT option_name, CHAR_LENGTH(option_value) AS size_bytes FROM wp_options WHERE autoload='yes' ORDER BY size_bytes DESC LIMIT 20;"

Mình thường thấy những “thủ phạm” là: _transient_* (expired nhưng chưa xóa), theme_mods_*, cron_schedules, và options từ plugin đã gỡ rồi.

Bước 3: Đếm post revisions

wp db query "SELECT COUNT(*) FROM wp_posts WHERE post_type='revision';"

Nếu con số này lớn hơn 3 lần số bài đã xuất bản, bạn đang lưu quá nhiều revision. Mình gặp site có 10.000 revision chỉ cho 200 bài viết — tỷ lệ 50:1!

Bước 4: Đếm expired transients

wp db query "SELECT COUNT(*) FROM wp_options WHERE option_name LIKE '_transient_%' AND option_name NOT LIKE '_transient_timeout_%';"

Nếu wp_options của bạn có hơn 1.000 rows, expired transients chắc chắn là nguyên nhân.

Bước 5: Kiểm tra orphaned postmeta

wp db query "SELECT COUNT(*) FROM wp_postmeta WHERE post_id NOT IN (SELECT ID FROM wp_posts);"

Orphaned metadata là metadata của post đã bị xóa nhưng metadata còn ở lại. Hoàn toàn vô dụng.

Cách Dọn Dẹp Database WordPress Từng Bước

Ok, bây giờ mình bắt đầu dọn dẹp. Lưu ý quan trọng: BACKUP DATABASE TRƯỚC KHI LÀM BẤT KỲ THAY ĐỔI NÀO. Bạn không thể rollback nếu không có backup.

Bước 1: Backup database

wp db export /tmp/backup-before-cleanup.sql --add-drop-table

Hoặc nếu bạn dùng hosting panel (cPanel, Plesk), dùng phpMyAdmin > Export > Custom > Select all tables > Go.

Bước 2: Giới hạn post revisions

Mở file wp-config.php và thêm dòng này trước /* That's all, stop editing! */:

define( 'WP_POST_REVISIONS', 3 );

Điều này giữ lại chỉ 3 revision gần nhất cho mỗi bài. Lưu ý: đừng đặt bằng 0 nếu bạn chưa chắc — một số plugin backup dependency cần revision. Mình khuyên dùng 3-5 là vừa phải.

Bước 3: Xóa post revisions cũ

wp db query "DELETE FROM wp_postmeta WHERE post_id IN (SELECT ID FROM wp_posts WHERE post_type='revision');"
wp db query "DELETE FROM wp_posts WHERE post_type='revision';"

Lưu ý: mình xóa postmeta trước, rồi mới xóa posts. Nếu làm ngược lại, bạn sẽ tạo thêm orphaned metadata. Nhiều bạn hay bị lỗi ở bước này.

Bước 4: Xóa expired transients

wp transient delete-all

Hoặc nếu bạn muốn chính xác hơn, dùng SQL:

wp db query "DELETE FROM wp_options WHERE option_name LIKE '_transient_timeout_%' AND option_value < UNIX_TIMESTAMP();"
wp db query "DELETE a FROM wp_options a LEFT JOIN wp_options b ON REPLACE(a.option_name, '_timeout_', '_') = b.option_name WHERE a.option_name LIKE '_transient_timeout_%' AND b.option_name IS NULL;"

Cách đơn giản nhất vẫn là wp transient delete-all — nó chỉ xóa expired, không ảnh hưởng transients còn hạn.

Bước 5: Xóa orphaned postmeta

wp db query "DELETE FROM wp_postmeta WHERE post_id NOT IN (SELECT ID FROM wp_posts);"

Lệnh này xóa tất cả metadata mà post_id không tồn tại nữa. An toàn vì dữ liệu này hoàn toàn vô dụng.

Bước 6: Xóa spam comments và trash

wp comment delete $(wp comment list --status=spam --format=ids) --force
wp comment delete $(wp comment list --status=trash --format=ids) --force
wp post delete $(wp post list --post_status=trash --format=ids) --force

Lưu ý: --force bỏ qua trash và xóa ngay. Chỉ dùng khi bạn chắc chắn muốn xóa.

Bước 7: Dọn dẹp autoloaded options

Kiểm tra lại những option lớn nhất, và nếu phát hiện options từ plugin đã gỡ:

wp db query "SELECT option_name FROM wp_options WHERE autoload='yes' ORDER BY CHAR_LENGTH(option_value) DESC LIMIT 10;"

Nếu bạn thấy options như widget_recent_entries_* hay _site_transient_* từ plugin đã xóa, bạn có thể tắt autoload:

wp db query "UPDATE wp_options SET autoload='no' WHERE option_name='ten_option_cu';"

Nhưng ĐỪNG TẠT AUToload CỦA: siteurl, home, blogname, active_plugins, user_roles. Tắt autoload của những option này sẽ làm site break.

Cách Optimize Database Tables Sau Khi Dọn Dẹp

Sau khi xóa dữ liệu, tables sẽ bị fragmented — giống như ổ cứng sau khi xóa file. Bạn cần OPTIMIZE TABLE để phục hồi không gian và giảm disk I/O.

Kiểm tra kích thước table và fragmentation

wp db query "SELECT TABLE_NAME, ROUND(((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024), 2) AS size_mb, ROUND((DATA_FREE / 1024 / 1024), 2) AS free_mb FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() ORDER BY size_mb DESC;"

Cột free_mb là không gian có thể phục hồi. Nếu thấy con số lớn hơn 10MB bất kỳ table nào, đó là fragmentation.

Chạy OPTIMIZE TABLE

wp db optimize

Hoặc specific tables:

wp db query "OPTIMIZE TABLE wp_posts, wp_postmeta, wp_options, wp_comments;"

Lưu ý: OPTIMIZE TABLE khóa table trong quá trình optimize. Trên site có traffic cao, bạn nên chạy vào giờ thấp điểm (2-4h sáng). Trên VPS có Itanium CPU và SSD, quá trình này chỉ mất vài giây đến vài phút.

Dùng Plugin Để Tự Động Dọn Dẹp Database

Nếu bạn không quen dùng command line, có 3 plugin mình khuyên dùng:

1. WP-Sweep (Miễn phí)

Đây là plugin mình thích nhất vì nó không dùng direct SQL DELETE. Nó dùng WordPress core functions để xóa, an toàn hơn. Nó xóa post revisions, auto-drafts, trashed posts, orphaned metadata, expired transients, và oEmbed caches.

2. WP-Optimize (Miễn phí + Premium)

Tích hợp cả database cleanup và page caching. Có lên lịch tự động dọn dẹp hàng tuần. Phiên Premium thêm image compression và lazy load.

3. Advanced Database Cleaner (Miễn phí + Pro)

Cho phép xem danh sách table từ plugin đã gỡ, xóa dữ liệu cụ thể, và lên lịch cleanup tự động. Bản Pro thêm multisite support.

Mình nghĩ bắt đầu bằng WP-Sweep là đủ. Sau đó khi đã quen, bạn chuyển sang WP-CLI để tự động hóa.

Cách Tự Động Hóa Database Cleanup Bằng Cron

Một lần dọn dẹp là chưa đủ. Bạn cần thiết lập cron job để tự động dọn dẹp hàng tuần. Mình thích dùng WP-CLI cron vì không cần Linux crontab.

Tạo WP-Cron schedule

Thêm vào functions.php của theme hoặc plugin custom:

add_filter( 'cron_schedules', function( $schedules ) {
    $schedules['weekly'] = array(
        'interval' => 604800,
        'display'  => 'Once Weekly'
    );
    return $schedules;
});

// Schedule cleanup event
if ( ! wp_next_scheduled( 'auto_db_cleanup' ) ) {
    wp_schedule_event( time(), 'weekly', 'auto_db_cleanup' );
}

add_action( 'auto_db_cleanup', function() {
    // Delete expired transients
    if ( function_exists( 'wp_transient_delete_all' ) ) {
        // Use WP-CLI if available via shell
    }
    // Limit revisions
    $revisions = get_posts( array(
        'post_type'      => 'revision',
        'posts_per_page' => -1,
        'fields'         => 'ids',
        'offset'         => 50,
    ) );
    foreach ( $revisions as $revision_id ) {
        wp_delete_post_revision( $revision_id );
    }
});

Hoặc đơn giản hơn, dùng Linux crontab trên VPS:

# Run every Sunday at 3 AM
0 3 * * 0 sudo -u www-data wp --path=/var/www/yoursite/public_html transient delete-all --allow-root
0 3 * * 0 sudo -u www-data wp --path=/var/www/yoursite/public_html db optimize --allow-root

Mình thích cách Linux crontab hơn vì nó chạy được cả khi WordPress bị lỗi.

Database Optimization Bao Nhiêu Thời Gian Chạy Một Lần?

Mình khuyên bạn thực hiện dọn dẹp toàn diện 3 tháng một lần, và tự động cleanup hàng tuần bằng cron. Cụ thể:

  • Hàng tuần: Xóa expired transients, xóa spam comments, xóa auto-drafts.
  • Hàng tháng: Chạy OPTIMIZE TABLE, kiểm tra autoload size.
  • 3 tháng một lần: Full audit — kiểm tra orphaned metadata, dọn dẹp options từ plugin cũ, review table sizes.

Nếu bạn publish 5+ bài mỗi ngày hoặc site có ecommerce, nên tăng lên hàng tuần cho tất cả.

Troubleshooting: 5 Lỗi Thường Gặp Khi Optimize Database

1. "MySQL server has gone away"

Nguyên nhân: Table quá lớn, hết memory trong quá trình OPTIMIZE. Fix: tăng max_allowed_packet trong my.cnf lên 64M hoặc 128M, rồi restart MySQL.

# /etc/mysql/my.cnf
[mysqld]
max_allowed_packet = 128M

2. "Lock wait timeout exceeded"

Nguyên nhân: Site vẫn đang chạy traffic khi bạn optimize. Fix: chạy vào giờ thấp điểm, hoặc dùng wp db optimize vì nó tự skip locked tables.

3. Site báo "Error establishing a database connection"

Nguyên nhân: Bạn có thể đã xóa nhầm wp_options rows quan trọng. Fix: restore từ backup wp db import /tmp/backup-before-cleanup.sql. Đây là lý do mình luôn nói BACKUP TRƯỚC.

4. Autoload size không giảm sau khi cleanup

Nguyên nhân: Plugin vẫn đang ghi dữ liệu vào autoload. Fix: dùng Query Monitor plugin để xem plugin nào đang set autoload='yes'. Vào wp_options, tắt autoload của những option không cần thiết.

5. Site vẫn chậm sau khi optimize

Nguyên nhân: Database có thể không phải bottleneck. Dùng wp profile để check:

wp profile stage --all --path=/var/www/yoursite/public_html

Nếu thấy "query" không phải phase chậm nhất, vấn đề có thể là PHP-FPM, hoặc asset loading. Tham khảo bài PHP-FPM và OPcache Tuning của mình để optimize thêm.

Checklist 7 Bước Dọn Dẹp Database WordPress

Đây là tóm tắt nhanh để bạn làm theo thứ tự:

  1. Backup databasewp db export
  2. Giới hạn revisionsdefine('WP_POST_REVISIONS', 3) trong wp-config.php
  3. Xóa revisions cũ — Xóa postmeta trước, rồi mới xóa posts
  4. Xóa expired transientswp transient delete-all
  5. Xóa orphaned metadata — SQL DELETE WHERE post_id NOT IN
  6. Optimize tableswp db optimize
  7. Thiết lập cron tự động — Weekly cleanup, monthly optimize

Mình đã áp dụng quy trình này cho hơn 30 website WordPress, và trung bình TTFB giảm 200-400ms, query time giảm 40-60%. Đặc biệt hiệu quả với site có nhiều plugin hoặc site chạy WooCommerce.

Nếu bạn có bất kỳ vấn đề gì khi làm theo hướng dẫn này, cứ để lại comment nhé. Mình sẽ giải đáp cụ thể cho từng trường hợp.

Thanh Tùng

Mình là Thanh Tùng. Bạn bè gọi mình là "bác sĩ máy tính" vì hễ máy nào có vấn đề là mình muốn mò vào xem sao. Mình viết hướng dẫn theo cách mà mình mong người khác đã viết cho mình ngày xưa — từng bước rõ ràng, không bỏ sót, và nói luôn cái gì hay bị lỗi. Ngoài giờ làm mình chơi guitar, nuôi mèo, và có một con VPS riêng dành riêng cho việc cài thử đủ thứ linh tinh.

Xem tất cả bài viết →

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *