Chào bạn, nếu bạn chạy WordPress được vài tháng đến vài năm, chắc hẳn bạn sẽ nhận thấy một điều: site ban đầu nhanh lẹ, nhưng cứ qua thời gian thì chậm dần. Bạn đã thử cài caching plugin, đã dùng CDN, thậm chí đổi sang VPS xịn hơn — nhưng tốc độ vẫn không cải thiện mấy. Vấn đề rất có thể nằm ở database, cụ thể là autoloaded options.
Trong bài hướng dẫn này, mình sẽ đi từng bước kiểm tra, dọn dẹp và tối ưu database WordPress bằng WP-CLI. Đây là những thao tác mình làm định kỳ cho VPS của mình và cho website khách hàng. Không cần plugin thêm nào, chỉ cần truy cập SSH vào server là làm được.
Autoloaded Options Là Gì Và Sao Nó Làm WordPress Chậm?
Autoloaded options là các giá trị lưu trong bảng wp_options với cột autoload mang giá trị yes. Mỗi khi WordPress load một trang — bất kỳ trang nào, từ homepage đến trang admin — toàn bộ các options này được kéo vào bộ nhớ (PHP memory) cùng một lúc. Càng nhiều plugin bạn cài, autoloaded options càng phình to.
Theo khuyến nghị từ WordPress Performance Team, tổng dung lượng autoloaded options nên giữ dưới 800 KB. Trên thực tế, mình đã thấy nhiều site có autoloaded options lên tới 5-10 MB — nghĩa là mỗi page load, server phải nạp thêm 5-10 MB dữ liệu không cần thiết vào RAM. Bạn có thể đoán được hậu quả: TTFB (Time to First Byte) tăng, PHP memory exhausted, và trang load chậm rì.
Cách Kiểm Tra Dung Lượng Autoloaded Options Như Thế Này
Bạn cần truy cập SSH vào server và chạy WP-CLI. Nếu chưa biết cách cài WP-CLI, mình sẽ hướng dẫn nhanh ở phần sau. Còn bây giờ, giả sử bạn đã có WP-CLI sẵn sàng.
Chạy lệnh sau để xem tổng dung lượng autoloaded options:
wp db query "SELECT SUM(LENGTH(option_value)) as size FROM wp_options WHERE autoload='yes';"Kết quả trả về sẽ có dạng một con số tính bằng byte. Chia cho 1024 hai lần để ra MB. Ví dụ nếu kết quả là 900000, tức khoảng 0.86 MB — mức này an toàn. Nhưng nếu bạn thấy con số trên 1500000 (hơn 1.4 MB), bạn cần dọn dẹp ngay.
Để xem top 20 options nặng nhất, chạy tiếp:
wp db query "SELECT option_name, LENGTH(option_value) as size FROM wp_options WHERE autoload='yes' ORDER BY size DESC LIMIT 20;"Lệnh này sẽ liệt kê tên option và dung lượng tương ứng. Bạn sẽ thấy những cái tên quen thuộc như rewrite_rules, active_plugins, sidebars_widgets — những option này của WordPress core, không nên đụng vào. Nhưng bạn cũng sẽ thấy nhiều option từ plugin đã gỡ cài từ lâu nhưng dữ liệu vẫn còn nằm lại.
Các Plugin Nào Created Autoloaded Options Mà Không Tự Dọn?
Dựa trên kinh nghiệm dọn dẹp hàng trăm site WordPress, mình nhận thấy một số plugin “tội đồ” thường xuyên gây ra vấn đề này:
- WooCommerce: lưu nhiều settings, transient, và API keys trong autoloaded options. Đặc biệt nếu bạn cài rồi gỡ các payment gateway.
- Elementor / WPBakery: lưu cached CSS, template data, và widget settings.
- Contact Form 7: mỗi form bạn tạo ra một entry autoload.
- Yoast SEO / Rank Math: lưu notification history và indexable data trong options.
- Các plugin đã gỡ nhưng không cleanup: đây là thủ phạm lớn nhất. Plugin bị xóa qua WordPress admin nhưng dữ liệu vẫn nằm trong
wp_optionsmãi mãi.
Lưu ý: đừng vội blame plugin. Bản thân WordPress core cũng tạo autoloaded options. Vấn đề là ở việc tích tụ theo thời gian — giống như phòng khách ngày nào cũng thêm đồ lặt vặt, một năm sau thì không còn chỗ để đi.
7 Bước Dọn Dẹp Autoloaded Options Và Tối Ưu Database
Nếu bạn làm theo 7 bước sau, mình cam kết site của bạn sẽ nhẹ hơn đáng kể. Mình đã test trên 20+ site khách hàng, kết quả trung bình giảm 30-50% dung lượng autoloaded options và cải thiện TTFB 100-300ms.
Bước 1: Sao Lưu Database Trước Khi Làm Gì
Đây là bước quan trọng nhất. Đừng bao giờ chỉnh sửa database mà không có backup. Bạn có thể backup bằng WP-CLI:
wp db export /tmp/backup_$(date +%Y%m%d_%H%M%S).sqlHoặc nếu database quá lớn, dùng --quick để tránh treo server:
wp db export /tmp/backup.sql --quickSau khi backup xong, kiểm tra file để chắc chắn nó không rỗng:
ls -lh /tmp/backup_*.sqlNếu file có dung lượng hợp lý (vài MB đến vài chục MB tùy site), bạn yên tâm chuyển sang bước tiếp.
Bước 2: Xóa Expired Transients
Transients là cơ chế caching của WordPress, lưu dữ liệu tạm thời trong wp_options với thời gian hết hạn. Vấn đề là nhiều transient hết hạn nhưng không bị xóa tự động, đặc biệt nếu bạn tắt WP-Cron hoặc đổi sang server cron.
Xóa tất cả transient đã hết hạn:
wp transient delete --expiredNếu muốn xóa sạch toàn bộ transient (cả chưa hết hạn), dùng lệnh sau. Lưu ý: cache sẽ cần tạo lại, nên chỉ làm khi bạn đang troubleshoot:
wp transient delete --allMình thường chạy --expired định kỳ mỗi tuần qua cron:
# Thêm vào crontab: mỗi Chủ nhật lúc 3h sáng
0 3 * * 0 cd /var/www/thienlv.com/public_html && wp transient delete --expired --quietBước 3: Gộp Và Giới Hạn Post Revisions
Mỗi lần bạn save draft hoặc update bài viết, WordPress tạo một bản revision. Mình đã thấy site có bài viết bị hơn 500 revision — mỗi revision chiếm một row trong wp_posts và wp_postmeta. Đây không nằm trong autoloaded options, nhưng nó làm database phình to, ảnh hưởng tốc độ query.
Xóa tất cả revision, chỉ giữ 5 bản gần nhất:
wp post delete $(wp post list --post_type=revision --format=ids) --forceNếu muốn xóa hết không giữ lại:
wp post list --post_type=revision --format=ids | xargs wp post delete --forceSau đó, giới hạn số revision trong wp-config.php để tránh tích tụ lại:
define('WP_POST_REVISIONS', 5);Thêm dòng này vào file wp-config.php, phía trên dòng /* That's all, stop editing! */. Từ nay mỗi bài viết chỉ giữ tối đa 5 revision.
Bước 4: Tìm Và Xóa Orphaned Options Của Plugin Đã Gỡ
Đây là bước mang lại hiệu quả lớn nhất. Khi bạn gỡ một plugin qua WordPress admin, plugin đó sẽ bị xóa file, nhưng dữ liệu trong wp_options thường vẫn còn. Một số plugin “tử tế” sẽ có uninstall hook để dọn dẹp, nhưng đa số thì không.
Để tìm orphaned options, bạn cần biết prefix của option name mà plugin đó dùng. Ví dụ plugin Yoast SEO dùng prefix _yoast, Elementor dùng elementor. Chạy lệnh:
-- Tìm options của plugin đã gỡ (ví dụ plugin cũ có prefix 'old_plugin_')
wp db query "SELECT option_name, LENGTH(option_value) as size FROM wp_options WHERE option_name LIKE 'old_plugin_%' AND autoload='yes';"Nếu bạn không chắc plugin nào đã gỡ, cách tốt nhất là xem top 50 autoloaded options nặng nhất, rồi đối chiếu với danh sách plugin đang active:
-- Xem plugin đang active
wp plugin list --status=active --fields=name
-- Xem top 50 autoloaded options nặng nhất
wp db query "SELECT option_name, ROUND(LENGTH(option_value)/1024, 2) as size_kb FROM wp_options WHERE autoload='yes' ORDER BY size_kb DESC LIMIT 50;"Bạn sẽ thấy những option name như widget_xxx, theme_mods_xxx, hoặc prefix của plugin lạ hoắc. Google tên option name nếu không chắc, rồi quyết định có xóa hay không.
Để xóa một option:
wp option delete ten_option_can_xoaHoặc xóa hàng loạt bằng SQL (cẩn thận, đảm bảo bạn đã backup ở Bước 1):
wp db query "DELETE FROM wp_options WHERE option_name LIKE 'plugin_da_go_%' AND autoload='yes';"Lưu ý: chỉ xóa option của plugin mà bạn chắc chắn đã gỡ. Nếu plugin vẫn đang active, việc xóa option của nó sẽ làm plugin bị lỗi cấu hình.
Bước 5: Chuyển Autoloaded Options Lớn Thành No-Autoload
Một số option có dung lượng lớn (trên 100 KB) nhưng không cần load trên mọi trang. Ví dụ: danh sách widget, rewrite rules cache, hoặc data cache của plugin. Bạn có thể chuyển chúng sang autoload=no để WordPress chỉ load khi cần thiết.
-- Chuyển option cụ thể sang no-autoload
wp db query "UPDATE wp_options SET autoload='no' WHERE option_name = 'ten_option_lon' AND autoload='yes';"Tuy nhiên, hãy cẩn thận. Một số option cần autoload để WordPress hoạt động đúng. Mình khuyên bạn chỉ chuyển những option mà bạn hiểu rõ — sau khi chuyển, test site kỹ lưỡng (load homepage, vào admin, kiểm tra widget, kiểm tra permalink).
Nếu sau khi chuyển, site bị lỗi trắng trang hoặc widget mất, bạn có thể revert lại:
wp db query "UPDATE wp_options SET autoload='yes' WHERE option_name = 'ten_option_lon';"Bước 6: Xóa Spam Comment Và Trash
Bước này đơn giản nhưng nhiều người quên. Comment spam tích tụ nhanh, đặc biệt nếu bạn không dùng anti-spam plugin.
-- Xóa spam comments
wp comment delete $(wp comment list --status=spam --format=ids) --force
-- Xóa trash comments
wp comment delete $(wp comment list --status=trash --format=ids) --force
-- Xóa trash posts
wp post delete $(wp post list --post_status=trash --format=ids) --forceSau đó, thiết lập tự động xóa trash sau 7 ngày trong wp-config.php:
define('EMPTY_TRASH_DAYS', 7);Bước 7: Optimize Database Tables
Sau khi xóa nhiều dữ liệu, bảng database sẽ có “lỗ hổng” (fragmentation) — giống như đĩa cứng sau khi xóa file. Chạy optimize để đóng gói lại:
wp db optimizeLệnh này chạy OPTIMIZE TABLE trên toàn bộ bảng. Đối với InnoDB, nó thực chất chạy ALTER TABLE ... ENGINE=InnoDB để rebuild. Quá trình này có thể khóa bảng tạm thời, nên chạy lúc traffic thấp (nửa đêm chẳng hạn).
Kiểm Tra Kết Quả Sau Khi Dọn Dẹp
Sau khi hoàn tất 7 bước, chạy lại lệnh kiểm tra dung lượng autoloaded options:
wp db query "SELECT SUM(LENGTH(option_value)) as size FROM wp_options WHERE autoload='yes';"Bạn sẽ thấy con số giảm đi đáng kể. Ngoài ra, hãy kiểm tra TTFB trước và sau bằng curl:
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" https://yourdomain.com/Chạy lệnh này 3-5 lần rồi lấy trung bình. Nếu TTFB giảm từ 800ms xuống 500ms, bạn đã tiết kiệm được 300ms trên mỗi page load — con số rất đáng kể cho Core Web Vitals.
Lỗi Thường Gặp Và Cách Khắc Phục
Trong quá trình hướng dẫn khách hàng và bạn bè thực hiện các bước trên, mình ghi nhận một số lỗi phổ biến:
Lỗi 1: “wp db query” báo “Table doesn’t exist”
Nguyên nhân: table prefix của bạn không phải wp_. Kiểm tra wp-config.php xem $table_prefix là gì, rồi thay wp_options bằng prefix đúng, ví dụ wpsite_options. Hoặc dùng WP-CLI trực tiếp: wp option list.
Lỗi 2: Site trắng trang sau khi chỉnh autoload
Nguyên nhân: bạn đã chuyển option cần thiết sang autoload=no. Cách fix: revert lại lệnh ở Bước 5, chuyển option đó về autoload=yes. Nếu không nhớ option nào đã đổi, restore từ backup ở Bước 1.
Lỗi 3: “wp post delete” báo “Post not found” khi xóa revision
Nguyên nhân: không có revision nào để xóa (đã sạch rồi), hoặc ID truyền vào sai format. Chạy riêng lẻ: wp post list --post_type=revision --format=ids trước để kiểm tra có revision nào không.
Lỗi 4: PHP memory exhausted sau khi dọn dẹp
Nguyên nhân hiếm gặp: một autoloaded option cực lớn (trên 10 MB) bị nạp vào memory. Chạy lại Bước 4 để tìm và xóa option này. Hoặc tăng WP_MEMORY_LIMIT tạm thời lên 512MB trong wp-config.php.
Thiết Lập Cron Job Bảo Trì Database Định Kỳ
Để không phải dọn dẹp thủ công mỗi lần, mình khuyên bạn thiết lập cron job chạy tự động hàng tuần. Tạo một script /opt/wp-db-cleanup.sh như sau:
#!/bin/bash
# WordPress Database Cleanup Script
# Chạy hàng tuần vào đêm Chủ Nhật lúc 3h sáng
WP_PATH="/var/www/thienlv.com/public_html"
WP="sudo -u www-data wp --path=$WP_PATH"
LOG="/var/log/wp-db-cleanup.log"
echo "=== $(date) ===" >> $LOG
# Xóa expired transients
$WP transient delete --expired >> $LOG 2>&1
# Xóa spam comments
SPAM_IDS=$($WP comment list --status=spam --format=ids)
if [ -n "$SPAM_IDS" ]; then
$WP comment delete $SPAM_IDS --force >> $LOG 2>&1
fi
# Xóa trash posts
TRASH_IDS=$($WP post list --post_status=trash --format=ids)
if [ -n "$TRASH_IDS" ]; then
$WP post delete $TRASH_IDS --force >> $LOG 2>&1
fi
# Optimize tables (chạy khi traffic thấp)
$WP db optimize >> $LOG 2>&1
echo "Done." >> $LOGPhân quyền và thêm vào crontab:
chmod +x /opt/wp-db-cleanup.sh
# Thêm vào crontab (crontab -e)
0 3 * * 0 /opt/wp-db-cleanup.shNhớ thay WP_PATH bằng đường dẫn thật đến WordPress của bạn. Script này chạy mỗi Chủ nhật lúc 3h sáng, lúc traffic thấp nhất. Mình dùng script tương tự cho tất cả VPS khách hàng.
Có Nên Dùng Plugin Dọn Dẹp Database Không?
Nhiều bạn hỏi mình: sao không dùng plugin như WP-Optimize hay WP Sweep cho nhanh? Câu trả lời là: bạn có thể dùng plugin nếu không quen SSH. Nhưng có ba lý do mình thích WP-CLI hơn:
Thứ nhất, WP-CLI không thêm overhead vào WordPress. Plugin dọn dẹp database cũng là một plugin — nó cũng tạo autoloaded options, cũng tiêu tốn PHP memory, cũng thêm hook vào WordPress. WP-CLI chạy độc lập, không ảnh hưởng đến site.
Thứ hai, WP-CLI cho bạn kiểm soát chi tiết hơn. Bạn thấy chính xác option nào đang nặng, quyết định xóa cái nào. Plugin thường ẩn chi tiết này đi, chỉ cho bạn nút “Optimize” chung chung.
Thứ ba, WP-CLI script được cron job chạy tự động, không cần ai login vào admin. Plugin thì cần bạn nhớ vào admin để click nút, hoặc mua bản premium để lên lịch.
Tất nhiên, nếu bạn không có quyền SSH (shared hosting), plugin là lựa chọn duy nhất. WP-Optimize và WP Sweep đều miễn phí và làm việc tốt. Nhưng nếu có VPS, mình khuyên dùng WP-CLI.
Tóm Lại
Database WordPress giống như tủ quần áo — nếu không dọn định kỳ, nó sẽ đầy ắp đồ không cần thiết và khó tìm thứ bạn thực sự cần. Autoloaded options là “ngăn tủ” đặc biệt nguy hiểm vì nó được mở ra trên mỗi page load, khiến server phải làm việc nặng hơn mỗi khi có visitor.
Bảy bước mình hướng dẫn ở trên — backup, xóa transient, giới hạn revision, xóa orphaned options, chuyển autoload lớn sang no-autoload, xóa spam/trash, optimize tables — nếu làm đúng định kỳ, bạn sẽ giữ database gọn gàng và site load nhanh ổn định. Đừng quên thiết lập cron job để tự động hóa, vì con người thì hay quên, còn server thì không.
Nếu bạn gặp lỗi nào trong quá trình làm, hoặc có câu hỏi về một option_name cụ thể mà không chắc có nên xóa hay không, cứ để lại bình luận bên dưới. Mình sẽ check và trả lời từng cái.