WordPress Database Indexing: Hướng Dẫn A-Z Tối Ưu Query Giảm 50% TTFB

Câu trả lời nhanh
Database index giúp WordPress tìm dữ liệu nhanh hơn thay vì quét toàn bộ bảng. Tối ưu index cho wp_postmeta, wp_options và các custom table có thể giảm 50% TTFB. Dùng Query Monitor và EXPLAIN để tìm query chậm, thêm composite index cho meta_key + meta_value, và đo trước sau để xác nhận.

Mình đã xử lý hàng chục site WordPress chạy chậm, và 90% trường hợp nguyên nhân không phải ở plugin hay theme. Vấn đề nằm ở database. Một bảng wp_postmeta bị phình đến 500MB, một truy vấn WP_Query quét toàn bộ bảng vì thiếu index, một plugin legacy tự viết SELECT * mà không có WHERE tối ưu. Tất cả đều khiến TTFB tăng vọt và CPU server đình công.

WordPress Database Indexing tối ưu query giảm TTFB
Database indexing giúp giảm TTFB đáng kể cho WordPress server

Trong bài này, mình sẽ hướng dẫn bạn từ A đến Z cách tối ưu database WordPress bằng indexing — kỹ thuật mà nhiều người nghe thì biết nhưng ít ai thực sự làm đúng. Mình sẽ đi từng bước, có lệnh cụ thể, có cách kiểm tra trước và sau.

Database Index Là Gì Và Tại Sao WordPress Cần?

Index là cấu trúc dữ liệu giúp database tìm hàng nhanh hơn thay vì quét toàn bộ bảng (full table scan). Hãy tưởng tượng bạn tìm một từ trong quyển sách 1.000 trang. Không có mục lục, bạn lật từng trang. Có mục lục, bạn nhảy thẳng đến trang cần đọc. Đó chính xác là cách index hoạt động.

WordPress mặc định tạo index cho khóa chính (PRIMARY KEY) và một số cột như post_status, meta_key. Nhưng khi bạn cài thêm plugin, tạo Custom Post Type với nhiều meta fields, hoặc chạy WooCommerce với hàng chục nghìn sản phẩm, các index mặc định không đủ. Kết quả: mỗi request kéo theo 200+ query chậm dần dần.

Cách Kiểm Tra Database WordPress Có Bị Chậm Không?

Trước khi tối ưu, bạn cần đo. Không đo thì đoán mò, và đoán mò với database thì rất tốn tiền. Có ba công cụ mình dùng thường xuyên:

1. Query Monitor (plugin miễn phí): Cài plugin Query Monitor, mở bất kỳ trang nào trên site, nhìn thanh admin bar. Plugin này hiển thị tổng số query, thời gian thực thi, và đánh dấu các query chậm. Bạn sẽ thấy ngay query nào mất hơn 0.05 giây — đó là ứng viên cần index.

2. WP-CLI: Đăng nhập SSH vào server, chạy lệnh sau để xem query slow:

wp db query "SHOW VARIABLES LIKE 'slow_query%';"
wp db query "SHOW VARIABLES LIKE 'long_query_time';"

Nếu slow_query_log đang OFF, bật lên:

sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
# Thêm vào:
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 0.5

Khởi động lại MariaDB/MySQL và theo dõi file log sau 24 giờ. Mọi query mất hơn 0.5 giây sẽ bị ghi lại.

3. EXPLAIN trực tiếp: Khi đã tìm được query chậm, dùng EXPLAIN để xem database thực thi nó thế nào:

wp db query "EXPLAIN SELECT * FROM wp_postmeta WHERE meta_key = '_thumbnail_id' AND meta_value = '12345';"

Nếu cột type hiện ALL, nghĩa là full table scan. Nếu hiện ref hoặc range, index đang hoạt động. Mục tiêu là loại bỏ mọi ALL.

Các Bảng WordPress Nào Thường Thiếu Index Nhất?

Qua kinh nghiệm xử lý hàng chục site, mình thấy bốn bảng sau thường xuyên gặp vấn đề thiếu index nhất:

wp_postmeta: Bảng này phình nhanh nhất vì mọi plugin đều lưu data ở đây. Mặc định WordPress chỉ index meta_key, nhưng không index meta_value. Khi plugin query theo meta_value, database quét toàn bộ hàng.

wp_options: Cột autoload quyết định option nào được load mỗi request. Nếu có hàng nghìn option autoload = yes, mỗi request đều phải load hết. Không có index tối ưu cho autoload trong một số cấu hình MariaDB cũ.

wp_termswp_term_taxonomy: Hai bảng này thường JOIN với nhau. Nếu site có hàng nghìn category/tag, query có thể chậm vì thiếu composite index.

WooCommerce: Bảng wp_wc_product_meta_lookupwp_wc_order_product_lookup thường phình khi sản phẩm hoặc đơn hàng tăng. WooCommerce tự tạo index, nhưng một số phiên bản cũ có thể thiếu.

Hướng Dẫn Thêm Custom Index Cho WordPress Database

Giờ là phần hands-on. Mình sẽ hướng dẫn thêm index cho bảng wp_postmeta — bảng thường xuyên bị chậm nhất.

Bước 1: Backup database trước khi làm bất cứ thứ gì.

wp db export backup-before-index.sql --path=/var/www/thienlv.com/public_html

Không bao giờ bỏ qua bước này. Thêm index sai có thể làm site chậm hơn thay vì nhanh hơn.

Bước 2: Kiểm tra index hiện tại.

wp db query "SHOW INDEX FROM wp_postmeta;"

Bạn sẽ thấy các index mặc định: PRIMARY (meta_id), post_id, meta_key. Cột meta_value thường không có index.

Bước 3: Thêm composite index cho meta_key + meta_value.

wp db query "ALTER TABLE wp_postmeta ADD INDEX meta_key_value (meta_key(50), meta_value(50));"

Mình dùng prefix 50 ký tự cho cả hai cột vì meta_value thường dài, index toàn bộ cột sẽ tốn disk và RAM. 50 ký tự đầu đủ để phân biệt trong 99% trường hợp.

Bước 4: Kiểm tra lại bằng EXPLAIN.

wp db query "EXPLAIN SELECT post_id FROM wp_postmeta WHERE meta_key = '_thumbnail_id' AND meta_value = '12345';"

Lần này cột type phải hiện refrows giảm đáng kể — từ hàng nghìn xuống còn vài hàng.

Bước 5: Đo lại TTFB.

curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" https://yourdomain.com/

Chạy trước và sau khi thêm index để so sánh. Nếu TTFB giảm rõ rệt, bạn đã làm đúng.

Thêm Index Cho wp_options Để Giảm Autoload Overhead

Bảng wp_options chứa toàn bộ cấu hình site. Mỗi request, WordPress load tất cả option có autoload = yes. Nếu bảng này có 10.000+ autoload option, mỗi request đều nặng.

Kiểm tra số lượng autoload option:

wp db query "SELECT COUNT(*) FROM wp_options WHERE autoload = 'yes';"

Nếu con số trên 1.000, bạn cần dọn. Kiểm tra tổng kích thước autoload:

wp db query "SELECT SUM(LENGTH(option_value)) as total_bytes FROM wp_options WHERE autoload = 'yes';"

Nếu trên 1MB, đó là vấn đề. Thêm index cho autoload:

wp db query "ALTER TABLE wp_options ADD INDEX autoload (autoload, option_name);"

Sau đó, dọn các autoload không cần thiết:

# Xem top 20 autoload option lớn nhất
wp db query "SELECT option_name, LENGTH(option_value) as size FROM wp_options WHERE autoload = 'yes' ORDER BY size DESC LIMIT 20;"

Những option nào thuộc plugin đã gỡ hoặc không cần load mỗi request, set autoload = no:

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

Tối ƫ WP_Query Bằng pre_get_posts Và Meta Query Index

Nhiều developer viết meta_query trong WP_Query mà không biết mỗi meta_query đều JOIN với wp_postmeta. Nếu bạn query theo meta field không có index, server đình công.

Ví dụ query chậm:

$args = array(
    'post_type'      => 'product',
    'posts_per_page' => 10,
    'meta_query'     => array(
        array(
            'key'     => '_custom_price',
            'value'   => '1000000',
            'compare' => '<=',
            'type'    => 'NUMERIC',
        ),
    ),
);

Query này JOIN wp_postmeta và filter theo _custom_price. Nếu không có index, full table scan trên bảng postmeta.

Cách xử lý: dùng Custom Database Table thay vì postmeta cho dữ liệu query thường xuyên. Tạo bảng riêng:

wp db query "CREATE TABLE wp_product_prices (
    post_id BIGINT(20) UNSIGNED NOT NULL,
    price DECIMAL(10,2) NOT NULL,
    PRIMARY KEY (post_id),
    INDEX idx_price (price)
);"

Sau đó query trực tiếp từ bảng này thay vì meta_query:

global $wpdb;
$results = $wpdb->get_results(
    "SELECT p.* FROM {$wpdb->posts} p
     INNER JOIN wp_product_prices pr ON p.ID = pr.post_id
     WHERE pr.price <= 1000000
     AND p.post_type = 'product'
     AND p.post_status = 'publish'
     LIMIT 10"
);

Cách này nhanh hơn 10-50 lần so với meta_query, tùy thuộc vào số lượng sản phẩm.

Database Index Có Làm Chậm Site Khi Ghi Không?

Có. Đây là đánh đổi quan trọng cần hiểu. Index giúp SELECT nhanh hơn nhưng làm INSERT/UPDATE/DELETE chậm hơn vì database phải cập nhật cả index. Với WordPress, phần lớn request là SELECT (đọc), nên đánh đổi này đáng giá. Nhưng nếu bạn chạy WooCommerce với hàng nghìn đơn hàng mỗi ngày, cần cân nhắc.

Quy tắc mình áp dụng: index cho cột query thường xuyên trong SELECT, không index cho cột chỉ ghi. Đo tỷ lệ đọc/ghi trước khi quyết định. Nếu 95% read, thêm index. Nếu 50/50, cân nhắc kỹ.

Cách Xóa Index Nếu Làm Sai

Nếu sau khi thêm index mà site chậm hơn hoặc có lỗi, xóa index ngay:

# Xem tên index
wp db query "SHOW INDEX FROM wp_postmeta;"

# Xóa theo tên
wp db query "ALTER TABLE wp_postmeta DROP INDEX meta_key_value;"

Luôn ghi lại tên index bạn thêm vào file custom-indexes.sql để dễ quản lý:

-- Custom indexes added on 2026-08-07
-- wp_postmeta: meta_key_value (meta_key(50), meta_value(50))
-- wp_options: autoload (autoload, option_name)
ALTER TABLE wp_postmeta ADD INDEX meta_key_value (meta_key(50), meta_value(50));
ALTER TABLE wp_options ADD INDEX autoload (autoload, option_name);

Kết Luận: Database Index Là Kỹ Thuật Đáng Đầu Tư

Database indexing không khó, nhưng cần làm đúng. Mình đã thấy site WordPress giảm TTFB từ 1.2 giây xuống 0.3 giây chỉ bằng cách thêm đúng 2 index. Không cần đổi host, không cần plugin đắt tiền, chỉ cần hiểu database hoạt động thế nào và can thiệp đúng chỗ.

Bắt đầu bằng Query Monitor để tìm query chậm, dùng EXPLAIN để xác nhận full table scan, thêm index từng bước và đo lường trước sau. Nếu bạn đang chạy site trên VPS, hãy xem thêm bài cấu hình MariaDB cho WordPress để tối ưu toàn diện lớp database. Và nếu bạn đang dùng Redis, kết hợp Redis Object Cache với index để đạt hiệu suất tối đa.

Tối ưu database là quá trình liên tục. Khi site lớn lên, database phình, index cũ có thể không còn tối ưu. Kiểm tra định kỳ mỗi 3-6 tháng, và luôn backup trước khi thay đổi.

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 *