Khi website của bạn bắt đầu thu hút lượng truy cập lớn và phải xử lý khối lượng dữ liệu ngày càng tăng, việc tối ưu và mở rộng quy mô hệ thống là điều cực kỳ quan trọng. Đối với những trang web sử dụng WordPress, việc scale web dữ liệu lớn không chỉ đòi hỏi kiến thức về hạ tầng mà còn cần sự hiểu biết sâu sắc về cách tối ưu hóa nền tảng này.
Bài viết này sẽ cung cấp cho bạn những định hướng cơ bản và chiến lược cần thiết để đảm bảo website WordPress của bạn hoạt động mượt mà và hiệu quả ngay cả khi đối mặt với lượng truy cập khổng lồ.

Bài viết được cập nhật 25.10.2026. Trong bài viết này, tôi sẽ không đề cập đến những giải pháp như Delay JS hoặc Preload Cache theo kiểu hack điểm Google. Chúng ta sẽ nhìn nhận theo góc nhìn lập trình viên và cùng thảo luận về vấn đề cơ sở dữ liệu.
Tại sao bản gốc của WordPress không mở rộng tốt?
WordPress thường hoạt động khá nhanh, nhưng lại trở nên chậm chạp trên các trang lưu trữ lớn do những nguyên nhân chính sau đây:
- WP_Query sử dụng LEFT JOIN để kiểm tra sự tồn tại của các mục trong wp_postmeta và / hoặc wp_term_relationships.
- WP_Query sau đó phải sử dụng lệnh GROUP BY để lấy các ID bài viết duy nhất.
- WP_Query bắt buộc phải sắp xếp, thậm chí khi không cần thiết, thường là theo DATE DESC.
- Thiếu các chỉ mục quan trọng trong các bảng chính.
Nhiều plugin, chẳng hạn, sẽ join vào wp_postmeta và kiểm tra meta_value mà không sử dụng meta_key. WordPress giả định rằng tất cả việc sử dụng wp_postmeta sẽ là một join trên wp_posts.ID = wp_postmeta.post_id – điều này không phải lúc nào cũng đúng và việc bỏ qua vấn đề này không giúp ích gì.

Vấn đề LEFT JOIN có nghĩa là nếu bạn truy cập trang lưu trữ /cua-hang/, WP_Query sẽ thực hiện LEFT JOIN cho tất cả sản phẩm của bạn với tất cả các wp_postmeta và / hoặc wp_term_relationships tương ứng của chúng. Sau đó, nó cũng sắp xếp các giá trị này và cuối cùng trình bày cho bạn 20 sản phẩm hàng đầu để hiển thị trên trang.
Nếu bạn có 900.000 sản phẩm, điều này có nghĩa là 900.000 mục được join với 900.000 hàng postmeta và 900.000+ (tùy thuộc vào số lượng danh mục mỗi sản phẩm) term_relationships. Bằng cách viết lại các truy vấn này để sử dụng WHERE EXISTS thay vì LEFT JOIN, chúng ta có thể loại bỏ nhu cầu sử dụng GROUP BY để lấy các ID bài viết duy nhất. Điều này cung cấp cơ hội để loại bỏ thao tác sắp xếp và chỉ còn lại một truy vấn thường chỉ đọc 20 – 40 hàng từ cơ sở dữ liệu của bạn để cung cấp trang 1 của lưu trữ.
Đặc biệt, khi tải sản phẩm trong /cua-hang/, không có lợi ích gì khi tải các sản phẩm mới nhất được thêm vào. Tốt hơn nên sử dụng thứ tự sắp xếp tự nhiên của cơ sở dữ liệu.
Nếu bạn là một lập trình viên, hãy xử lý toàn bộ vấn đề trên để build cho khách một source WP hoàn thiện nhất.
Tại sao WooCommerce phiên bản gốc không mở rộng tốt?
WooCommerce đi kèm với các widget sidebar có mã kém, gây ra hai vấn đề lớn ảnh hưởng đến khả năng mở rộng:
- Phần lớn mã của widget và shortcode gây ra việc quét bảng, tức là đọc tất cả sản phẩm trong cơ sở dữ liệu của bạn trên nhiều/trang.
- Một số widget của họ (ví dụ: bộ lọc giá) xử lý tất cả các sản phẩm khớp bằng PHP.
Giải pháp tối ưu cho lập trình viên
Để thay thế các widget của WooCommerce, bạn có thể tối ưu hiệu suất như sau:
Giả sử bạn có một danh mục như sau:
Sách -> Sách giáo khoa -> Sách giáo khoa lớp 12
Khi danh mục cấp cao nhất “Sách” đã được đếm một lần, nó không cần phải đếm lại cho đến khi có sản phẩm mới được thêm/xóa hoặc thay đổi trong cửa hàng.
Điều này có nghĩa là khi người dùng truy cập vào danh mục phụ “Sách giáo khoa“, widget sẽ tái sử dụng kết quả truy vấn cho tất cả các danh mục cấp cao nhất đã được đếm. Tương tự, khi người dùng truy cập vào danh mục “Sách giáo khoa lớp 12“, nếu có bất kỳ danh mục phụ nào thì chỉ những danh mục đó mới cần được đếm. Điều này giúp tiết kiệm rất nhiều tài nguyên máy chủ. Ngoài ra, các truy vấn cũng nhanh hơn và sử dụng trực tiếp cơ sở dữ liệu để thực hiện việc đếm thay vì dựa vào mã PHP.

Hãy tối ưu cửa hàng webshop cho khách hàng của bạn theo phương pháp này khi website đạt dữ liệu lớn. Trong case study tối ưu cho khách hàng – web này khoảng 80k sản phẩm và hoạt động khá trơn tru.
Tại sao bộ nhớ đệm không đủ để giải quyết các vấn đề mở rộng?
Một số plugin bộ nhớ đệm có trả phí yêu thích của tôi bao gồm FlyingPress và Swift Performance. Tuy nhiên nó chỉ dành cho những trang web có cơ sở dữ liệu nhỏ hoặc trung bình.
Đối với các trang web lớn, caching không phải là giải pháp cho các vấn đề mở rộng quy mô vì những lý do sau:
- Hành vi tìm kiếm của Googlebot khác biệt so với người dùng: Các trang thường không được cache cho Googlebot (Đó là lý do tại sao khi bạn xem F12 ở trình duyệt có tính năng Disable Caching). Nếu Googlebot nhận thấy tốc độ tải trang chậm, thứ hạng SEO của bạn sẽ bị ảnh hưởng tiêu cực.
- Số lượng bộ lọc lớn: Không thể cache tất cả các tổ hợp bộ lọc vì sẽ tốn quá nhiều dung lượng đĩa. Hơn nữa, việc khởi tạo cache cũng sẽ mất quá nhiều thời gian.
- Hiệu suất cơ bản kém: Nếu một trang mất từ 10 đến 30 giây để tải, đĩa và CPU của máy chủ sẽ bị quá tải. Điều này khiến máy chủ khó cung cấp mức độ phản hồi tốt cho người dùng khác, ngay cả khi các trang họ yêu cầu đã được cache. Ngoài ra, các lần quét bảng dữ liệu gây ra việc đọc toàn bộ dữ liệu cho một truy vấn duy nhất sẽ làm vô hiệu hóa tất cả lợi ích của việc cache truy vấn MySQL, tức là chúng sẽ làm sạch cache cơ sở dữ liệu.
Bằng cách cải thiện hiệu suất cơ bản xuống dưới một giây, sau đó bạn có thể thêm caching ở mức trang để các trang được người dùng truy cập thường xuyên được cache. Điều này không chỉ giúp bạn vượt qua Googlebot và người dùng thông thường mà còn giúp trang web chịu được các đợt tăng lưu lượng truy cập.
Ví dụ khi web dữ liệu lớn, bạn nên cache trang chủ, trang giới thiệu… Còn các trang như bài viết hoặc sản phẩm thì bạn đặt lệnh cache khi có người click vào thì sẽ cache (và sẽ tự xóa cache sau một khoảng thời gian nhất định) để tiết kiệm bộ nhớ và tránh quá tải máy chủ.
Tại sao chức năng tìm kiếm căn bản không đáp ứng cho web lớn?
Chức năng tìm kiếm văn bản tự do đi kèm với WordPress hoàn toàn không thể mở rộng. Nguyên nhân là do SQL cơ sở sử dụng toán tử LIKE. Ví dụ, một tìm kiếm cho ‘quicksite microphone’ sẽ sử dụng câu truy vấn như:
WHERE description LIKE ‘%quicksite microphone%’
Ký hiệu % này có nghĩa là ký tự đại diện (wildcard). Việc có ký tự đại diện ở đầu câu lệnh LIKE khiến bất kỳ cơ sở dữ liệu nào cũng không thể sử dụng bất kỳ chỉ mục nào có thể tồn tại trên cột đó. Điều này đã được mã hóa theo cách để đảm bảo WordPress hoạt động trên công nghệ cũ nhất có thể.

Chỉ mục toàn văn (Fulltext indexes) là giải pháp thực sự ở đây – nhưng các phiên bản cũ của MySQL không có chỉ mục toàn văn, đặc biệt là trong Innodb. Điều này hiện không còn đúng nữa, và dù sao đi nữa, bạn nên sử dụng PerconaDB hoặc MariaDB thay vì MySQL. Cả hai hệ quản trị cơ sở dữ liệu này đều có sẵn chỉ mục toàn văn.
Hãy sử dụng Elastic Search cho các trang web cần dữ liệu lớn. Elastic Search hoàn toàn miễn phí và dễ sử dụng.
Đọc thêm: https://quicksite.vn/nhung-giai-phap-tim-kiem-toi-uu-nhat-cho-wordpress/
Tại sao phân trang căn bản và hầu hết các tính năng Load More đều không đáp ứng được cho web lớn?
Việc hiển thị số lượng sản phẩm trong thư viện buộc hệ thống phải đếm toàn bộ sản phẩm, điều này không cần thiết và gây tải không đáng có lên server.
Thực tế, phần lớn người dùng không vượt qua trang đầu tiên của thư viện mà họ sẽ sử dụng bộ lọc sản phẩm hoặc bài viết ngay lập tức. Với sự phổ biến của thiết bị di động và máy tính bảng ngày nay, việc cuộn trang liên tục là lựa chọn tiện lợi hơn cho người dùng.
Một số khách nước ngoài tôi làm việc đều yêu cầu chức năng Infinity Loadmore vì họ có bàn tay quá khổ hơn người châu Á, bấm nút trang 1,2,3 trên điện thoại rất khó khăn.
Những nỗ lực trước đây và hạn chế
Các nỗ lực trước đây nhằm triển khai tính năng cuộn vô hạn thường gặp phải vấn đề quan trọng:
Khi người dùng tìm được sản phẩm ưa thích, nhấp vào để xem chi tiết và sau đó nhấn nút “Back”, họ sẽ trở về đầu trang của thư viện sản phẩm. (thay vì đúng chỗ mà họ đã cuộn xuống lúc nãy)
Một số plugin đã cố gắng giải quyết bằng cách lưu số trang vào lịch sử trình duyệt, nhưng điều này gây nhầm lẫn khi người dùng trở lại giữa chừng mà không thấy sản phẩm nào ở trên. Có plugin khác lại cho phép cuộn vô hạn ngược lên, điều này càng gây rối rắm.
Nhiều plugin không giải quyết vấn đề này, khiến vị trí cuộn nằm ở cuối màn hình và tải trang tiếp theo. Điều này dẫn đến việc người dùng ở sai vị trí và có thể rời khỏi trang nếu sản phẩm họ xem nằm ở trang 3 hoặc 4. Ngoài ra, server phải chịu tải không cần thiết khi tải lại các trang đã được tải trước đó. Dù việc caching có thể giúp giảm tải, nhưng vẫn không cần thiết.

Giải pháp tối ưu cuộn vô hạn cho lập trình viên
Cuộn vô hạn cần thiết để loại bỏ phân trang, và loại bỏ phân trang là cần thiết cho tính mở rộng của hệ thống.
Khi người dùng nhấp vào một sản phẩm từ thư viện, sẽ lưu trữ toàn bộ thư viện vào hệ thống lưu trữ của trình duyệt cùng với vị trí cuộn hiện tại.
Điều này đảm bảo rằng khi người dùng quay lại bằng nút “Back”, trang thư viện sẽ được tải từ bộ nhớ trình duyệt và cuộn ngay đến vị trí mà họ đã rời khỏi.
Điều này có nghĩa là “Back” thực sự là “Back”. Người dùng nhấn “Back” và dù họ đang ở trang 20 của cuộn vô hạn, toàn bộ thư viện sẽ được tải ngay lập tức mà không cần thêm tài nguyên từ server.
Vị trí cuộn cũng được khôi phục chính xác. Điều này mang lại trải nghiệm như mong đợi cho người dùng và tiếp tục hành trình mua sắm của họ một cách mượt mà và liền mạch.
Giải pháp này không những giúp tối ưu cả tốc độ mà còn tăng trải nghiệm người dùng đáng kể. Bạn có thể cài preload viewport trước đó khoảng 250px-300px giúp khách hàng không phải chờ đợi quá trình tải thêm.
Chúc bạn thành công!







