Tại sao cần tối ưu cơ sở dữ liệu WordPress?
Theo thời gian, cơ sở dữ liệu WordPress tích tụ rất nhiều dữ liệu rác: bài viết revision, spam comment, transient hết hạn, và các bảng bị phân mảnh. Những dữ liệu này không chỉ làm phình to database mà còn ảnh hưởng đến tốc độ truy vấn, thời gian backup, và hiệu năng tổng thể của website.
Trong quá trình triển khai bảo trì website cho khách hàng tại Code Tốt, chúng tôi nhận thấy nhiều site có database lên đến 200-300MB chỉ vì revision và transient không được dọn dẹp. Bài viết này sẽ hướng dẫn bạn sử dụng WP-CLI để tự động hoá quy trình dọn dẹp database một cách an toàn và hiệu quả.
Hiểu về các loại dữ liệu rác trong WordPress
Post Revision
Mỗi lần bạn lưu bài viết, WordPress tự động tạo một bản revision. Với website có nhiều bài viết và nhiều lần chỉnh sửa, số lượng revision có thể lên đến hàng chục ngàn bản — mỗi bản lưu trữ toàn bộ nội dung bài viết trong bảng wp_posts.
Ví dụ: Một bài viết 2000 từ được chỉnh sửa 50 lần sẽ tạo ra 50 revision, mỗi revision chiếm ~2KB. Tổng cộng 100KB cho một bài — nhân với 100 bài viết, bạn đã có 10MB dữ liệu revision vô ích.
Spam Comment và Trash Comment
Các comment spam bị đánh dấu hoặc bị xoá vẫn nằm trong database cho đến khi bạn dọn dẹp thủ công. Một số website có hàng trăm ngàn spam comment, chiếm dung lượng đáng kể trong bảng wp_comments và wp_commentmeta.
Transient Hết Hạn
WordPress sử dụng transient API để cache dữ liệu tạm thời (kết quả query, API response, dữ liệu plugin). Nhiều transient có thời gian sống ngắn và tự động hết hạn, nhưng chúng không tự động bị xoá khỏi bảng wp_options. Một số website có thể tích tụ hàng ngàn transient đã hết hạn.
Bảng Bị Phân Mảnh
Sau nhiều lần thêm/xoá dữ liệu, các bảng MySQL bị phân mảnh (fragmented). Điều này làm chậm truy vấn SELECT và tăng dung lượng lưu trữ. Tối ưu bảng (OPTIMIZE TABLE) giúp giải phóng không gian và cải thiện hiệu năng.
Kiểm tra tình trạng database hiện tại
Trước khi dọn dẹp, hãy kiểm tra dung lượng database và số lượng dữ liệu rác:
# Kiểm tra dung lượng database
wp db size --tables
# Đếm số lượng revision
wp db query "SELECT COUNT(*) AS revisions FROM wp_posts WHERE post_type = 'revision'"
# Đếm spam comment
wp db query "SELECT COUNT(*) AS spam FROM wp_comments WHERE comment_approved = 'spam'"
# Đếm transient đã hết hạn
wp db query "SELECT COUNT(*) AS expired_transients FROM wp_options WHERE option_name LIKE '_transient_timeout_%' AND option_value < UNIX_TIMESTAMP()"
Giải thích: Lệnh wp db size --tables hiển thị dung lượng từng bảng. Truy vấn revision giúp bạn biết mức độ nghiêm trọng. Transient hết hạn được xác định bằng cách so sánh option_value (thời gian timeout) với UNIX_TIMESTAMP() hiện tại.
Luôn chạy wp db export trước khi thực hiện bất kỳ thao tác xoá nào — đây là nguyên tắc an toàn cơ bản mà bất kỳ ai quản trị WordPress cũng phải tuân thủ.
Dọn dẹp Post Revision
WP-CLI cung cấp lệnh wp post delete kết hợp với --force để xoá revision. Tuy nhiên, xoá từng revision một rất chậm. Cách hiệu quả hơn là dùng truy vấn SQL trực tiếp:
# Backup database trước khi xoá
wp db export /tmp/backup-before-clean.sql
# Xoá tất cả revision (chạy --dry-run trước)
wp db query "DELETE FROM wp_posts WHERE post_type = 'revision' AND post_date < NOW() - INTERVAL 30 DAY" --dry-run
# Nếu OK, chạy thật
wp db query "DELETE FROM wp_posts WHERE post_type = 'revision' AND post_date < NOW() - INTERVAL 30 DAY"
# Xoá postmeta của revision đã xoá
wp db query "DELETE pm FROM wp_postmeta pm LEFT JOIN wp_posts p ON pm.post_id = p.ID WHERE p.ID IS NULL"
Tại sao giữ revision 30 ngày? Trong thực tế, Khôi Pro khuyên bạn nên giữ lại revision trong 30 ngày gần nhất để đề phòng cần khôi phục nội dung. Chỉ xoá revision cũ hơn 30 ngày — vừa tiết kiệm dung lượng vừa giữ được safety net.
Lưu ý an toàn: Luôn dùng --dry-run trước. Lệnh DELETE không có WHERE clause sẽ xoá toàn bộ dữ liệu — một sai lầm rất dễ gặp khi bạn gõ lệnh trong lúc vội vàng.
Dọn dẹp Spam Comment và Trash Comment
Spam comment không chỉ chiếm dung lượng mà còn làm chậm truy vấn hiển thị comment. WP-CLI có lệnh riêng để xử lý:
# Xoá tất cả spam comment
wp comment delete $(wp comment list --status=spam --format=ids) --force
# Xoá comment trong trash
wp comment delete $(wp comment list --status=trash --format=ids) --force
# Hoặc dùng SQL trực tiếp (nhanh hơn với số lượng lớn)
wp db query "DELETE FROM wp_comments WHERE comment_approved = 'spam'"
wp db query "DELETE FROM wp_comments WHERE comment_approved = 'trash'"
wp db query "DELETE FROM wp_commentmeta WHERE comment_id NOT IN (SELECT comment_id FROM wp_comments)"
Với website có hàng trăm ngàn spam comment, dùng wp comment list có thể rất chậm. Trong trường hợp đó, SQL trực tiếp là lựa chọn tốt hơn. Tuy nhiên, hãy luôn backup trước khi chạy DELETE.
Dọn dẹp Transient Hết Hạn
Transient hết hạn là loại dữ liệu rác dễ bị bỏ qua nhất. Chúng nằm trong bảng wp_options với prefix _transient_ và _transient_timeout_:
# Xoá transient đã hết hạn
wp db query "DELETE FROM wp_options WHERE option_name LIKE '_transient_timeout_%' AND option_value < UNIX_TIMESTAMP()"
wp db query "DELETE FROM wp_options WHERE option_name LIKE '_transient_%' AND option_name NOT LIKE '_transient_timeout_%' AND option_name NOT IN (SELECT CONCAT('_transient_timeout_', SUBSTRING(option_name, 12)) FROM wp_options WHERE option_name LIKE '_transient_timeout_%')"
# Hoặc dùng WP-CLI command nếu có plugin hỗ trợ
wp transient delete --all --expired
Cách hoạt động: WordPress lưu transient theo cặp: _transient_ten_key (giá trị) và _transient_timeout_ten_key (thời gian hết hạn). Khi timeout đã qua, transient vẫn tồn tại trong database — WordPress chỉ kiểm tra timeout khi có code request transient đó. Nếu không có request nào gọi đến, transient “ma” sẽ ở lại mãi mãi.
Tối ưu bảng MySQL (OPTIMIZE TABLE)
Sau khi xoá dữ liệu, các bảng cần được tối ưu để giải phóng không gian và cải thiện hiệu năng:
# Tối ưu tất cả bảng WordPress
wp db optimize
# Hoặc tối ưu từng bảng cụ thể
wp db query "OPTIMIZE TABLE wp_posts, wp_postmeta, wp_comments, wp_commentmeta, wp_options, wp_term_relationships"
Lệnh wp db optimize tương đương với mysqlcheck --optimize — nó sắp xếp lại dữ liệu, loại bỏ fragment, và cập nhật index statistics. Sau optimize, dung lượng database có thể giảm 20-40%.
Tự động hoá với Bash Script và Cron
Thay vì chạy thủ công mỗi tháng, hãy tạo một script tự động và schedule qua cron. Đây là cách mà Code Tốt áp dụng cho tất cả website khách hàng — vừa tiết kiệm thời gian vừa đảm bảo database luôn sạch.
#!/bin/bash
# /usr/local/bin/wp-db-cleanup.sh
# Script dọn dẹp database WordPress tự động
WP_PATH="/var/www/html"
WP="wp --path=$WP_PATH"
LOG="/var/log/wp-db-cleanup.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] Bắt đầu dọn dẹp database..." >> $LOG
# 1. Backup
$WP db export "/tmp/backup-$DATE.sql" && echo " Backup OK" >> $LOG
# 2. Xoá revision cũ hơn 30 ngày
$WP db query "DELETE FROM wp_posts WHERE post_type = 'revision' AND post_date < NOW() - INTERVAL 30 DAY"
echo " Deleted revisions" >> $LOG
# 3. Xoá spam comment
$WP db query "DELETE FROM wp_comments WHERE comment_approved = 'spam'"
echo " Deleted spam comments" >> $LOG
# 4. Xoá transient hết hạn
$WP db query "DELETE FROM wp_options WHERE option_name LIKE '_transient_timeout_%' AND option_value < UNIX_TIMESTAMP()"
$WP db query "DELETE FROM wp_options WHERE option_name LIKE '_transient_%' AND option_name NOT LIKE '_transient_timeout_%' AND option_name NOT IN (SELECT CONCAT('_transient_timeout_', SUBSTRING(option_name, 12)) FROM wp_options WHERE option_name LIKE '_transient_timeout_%')"
echo " Deleted expired transients" >> $LOG
# 5. Tối ưu bảng
$WP db optimize
echo " Optimized tables" >> $LOG
# 6. Xoá backup cũ hơn 7 ngày
find /tmp/ -name "backup-*.sql" -mtime +7 -delete
echo " Cleaned old backups" >> $LOG
echo "[$DATE] Hoàn tất!" >> $LOG
Sau khi tạo script, thêm vào crontab để chạy hàng tuần:
# Chạy lúc 3:00 sáng Chủ Nhật hàng tuần
0 3 * * 0 /usr/local/bin/wp-db-cleanup.sh
Tại sao chạy hàng tuần? Với website có lượng comment và revision lớn, dọn dẹp hàng tháng có thể để rác tích tụ quá nhiều. Lịch hàng tuần giúp database luôn nhẹ, backup nhanh, và giảm thời gian restore khi cần.
Hạn chế Revision từ đầu
Phòng bệnh hơn chữa bệnh. Bạn có thể giới hạn số lượng revision ngay từ đầu bằng cách thêm vào wp-config.php:
// Giới hạn revision tối đa 5 bản mỗi bài viết
define('WP_POST_REVISIONS', 5);
// Hoặc tắt hoàn toàn (không khuyến khích)
// define('WP_POST_REVISIONS', false);
Giải thích: WP_POST_REVISIONS nhận giá trị số (giới hạn số bản revision) hoặc false (tắt hoàn toàn). Giá trị mặc định là true — không giới hạn. Đặt thành 5 là con số hợp lý: vừa đủ để rollback khi cần, vừa không làm phình database.
Tuy nhiên, hằng số này chỉ ảnh hưởng đến revision được tạo sau khi bạn thêm vào wp-config. Revision cũ vẫn tồn tại và cần được dọn dẹp bằng script ở trên.
Kết luận
Dọn dẹp database WordPress định kỳ là một trong những việc bảo trì quan trọng nhất nhưng thường bị bỏ qua. Với WP-CLI và một script tự động, bạn có thể:
- Giảm dung lượng database 30-50%
- Cải thiện tốc độ truy vấn và thời gian backup
- Giảm thời gian restore khi có sự cố
- Tự động hoá hoàn toàn với cron job
Hãy bắt đầu bằng cách kiểm tra database của bạn ngay hôm nay — bạn sẽ bất ngờ với lượng dữ liệu rác đã tích tụ.