Cách WordPress lưu dữ liệu Custom Fields – P2 – Database

Sau một loạt các bài viết về custom fields của mình, chắc giờ bạn cũng đã hiểu custom fields là gì rồi. Ở bài trước, chúng ta đang dừng ở đoạn WordPress gọi hàm update_metadata và lưu dữ liệu từ custom fields vào database. Nên bây giờ, chúng ta sẽ tiếp tục đi theo đường đi đó và tìm hiểu xem cách mà WordPress tổ chức và cấu trúc database như thế nào nhé.

Với database (chỉ trong MySQL), bạn có thể biết rằng nó được tổ chức theo dạng bảng và trong bảng có các cột và dòng. Mỗi một dòng được gọi là một bản ghi (record) và mỗi cột trong dòng đó được gọi là 1 trường (field). Để lưu các đối tượng vào database, cách đơn giản và phổ biến nhất đó chính là tạo một bảng với đầy đủ các cột tương ứng với các thuộc tính của đối tượng là được.

Lấy một ví dụ cụ thể như là Post trong WordPress đi. Một bài viết có một số thuộc tính như là tiêu đề, nội dung, ảnh đại diện, và các custom field. Liệu WordPress có lưu các thuộc tính này vào các cột trong bảng wp_posts hay không? Cùng tìm hiểu chi tiết ở dưới đây nhé.

Lần trước, chúng ta đã vọc các đoạn code của WordPress để hiểu được đường đi của dữ liệu như thế nào trong quá trình lưu các dữ liệu của custom field. Còn bây giờ, chúng ta sẽ xem xem ở phía database thì dữ liệu được xử lý như thế nào, và tất nhiên là không liên quan gì đến code nữa nhé.

Cấu trúc Database

Đối tượng và các custom field được đặt trong các cột trong bảng tương ứng trong database của WordPress
Các đối tượng và các custom field được đặt trong các cột trong bảng tương ứng trong WordPress

Bảng wp_posts có rất nhiều cột để mô tả cho đối tượng Post. Nó cũng giống như là với Term, Comment, hay User vậy. Nhìn vào bảng này, bạn sẽ thấy chỉ các cột cơ bản cần thiết và các thông tin cơ bản của các nội dung phổ biến như là post_title, post_content. Vậy thì cột là nào để lưu các giá trị của custom fields?

Chẳng có cột nào để làm việc đó cả. WordPress không làm theo cách thông thường mà mình đã nói đâu. Thay vào đó, WordPress chuyển qua sử dụng một bảng có các cột ngang thay vì cột dọc. Vì vậy, mỗi custom field lúc này lại trở thành một dòng. Khi đó, mỗi dòng đang không mô tả một đối tượng nào cả mà nó chỉ mô tả một thuộc tính riêng biệt nào đó thôi.

Ví dụ:

Giả sử như là chúng ta có các bảng được tổ chức theo cách thông thường như sau:

meta_idpost_idhcf_pricehcf_author
15$46metabox
26$52Anh Tran

Và đây là cách mà WordPress lưu dữ liệu trong thực tế:

meta_idpost_idmeta_keymeta_value
15hcf_price$46
25hcf_authormetabox
36hcf_price$52
46hcf_authorAnh Tran

Bạn thấy đấy, lúc đầu chúng ta chỉ có hai dòng thôi, và mỗi dòng có 2 cột bao gồm hai custom field. Nhưng ở bảng sau có tới 4 field. Bạn có thể tưởng tượng rằng chúng ta đã chuyển toàn bộ cột hcf_author xuống dưới cột hcf_price, rồi thêm các cột để định nghĩa key và giá trị. Như vậy, nếu bạn có N custom field và M post, thì số lượng dòng mà WordPress tạo ra trong bảng sẽ là M*N dòng.

Tất nhiên là con số này khá lớn đúng không, đặc biệt là khi bạn sử dụng các plugin thuộc nhóm khai thác triệt để custom field như WooCommerce, Sensie, hoặc sử dụng các custom field để mô tả cho các đối tượng siêu phức tạp.

Đọc thêm về: Tối ưu database cho custom field

Ưu nhược điểm

Mặc dù WordPress là một CMS nổi tiếng, nhưng tại sao nó vẫn sử dụng phương pháp không mấy hiệu quả kia để lưu dữ liệu cho custom field? Hẳn phải có lý do nào đó chứ. Hãy cùng tìm hiểu xem ưu nhược điểm của phương pháp này để biết tại sao nhé.

Ưu điểm

Khả năng tùy biến cao

Theo như cấu trúc bảng thông thường, thì một khi bạn thêm một custom field, bạn sẽ phải chạy một đoạn mã migration để thêm cột vào các dòng trong bảng. Sau đó, cấu trúc của bảng sẽ thay đổi.

Ngược lại, với bảng meta, không cần biết là bạn thêm bao nhiêu field vào và bạn đặt tên nó là gì, cấu trúc của bạn vẫn được giữ nguyên. Sẽ chỉ có một dòng được thêm vào trong bảng mà thôi.

Tính đa dạng

Căn cứ theo cấu trúc dữ liệu thông thường, thì tất cả các đối tượng trong bảng đều được mô tả mỗi cái trong một dòng và sẽ có cấu trúc giống nhau với các cột giống nhau. Nếu như bạn muốn mô tả một đối tượng khác, bạn buộc phải tạo một bảng khác. Tuy nhiên, WordPress có hỗ trợ custom post type để giúp bạn mô tả nhiều loại đối tượng khác nhau trong cùng một bảng (wp_post, wp_postmeta). Mà để làm điều đó, buộc WordPress phải sử dụng bảng meta. Nó phù hợp với các đối tượng có cấu trúc khác biệt và không cụ thể.

Bởi vì hai ưu điểm này, nên cấu trúc database của WordPress sẽ không thay đổi dù bạn có thêm bao nhiêu custom field đi chăng nữa. Cấu trúc của bảng wp_postmeta sẽ được giữ nguyên, dù đang mô tả cho đối tượng nào cũng vậy. Đó chính là lý do tại sao cần phải có thêm một bước là “migrate database” cho các website sử dụng cách cấu trúc dữ liệu theo cách thông thường. Điều này mang lại cho WordPress không chỉ khả năng tùy biến cao mà còn khá là đơn giản cho người dùng nữa đấy.

Nhược điểm

Hiệu suất truy vấn

Như đã nói ở trên, để tính ra số lượng dòng, chúng ta có công thức sau:

Số lượng dòng = Số lượng bài viết * Số lượng custom fields

Giả sử bạn có 20 custom fields, vào có 500 bài viết, thì bạn sẽ có 500*20=10,000 dòng trong database. Nghe có vẻ không quá lớn, cũng không quá nhỏ nhỉ. Nhưng blog của bạn có thể có tới 500 bài viết không? Thử nghĩ xem nếu một năm nữa khi số lượng bài viết của bạn tăng lên gấp đôi hay gấp ba thì sao? Lúc đó thì lại thành nhiều đó chứ.

Tuy nhiên, làm thế nào để truy vấn được với 20 custom field vào cùng một lúc? Ồ, tất nhiên là bạn phải cần tới 20 lệnh JOIN. Vì mỗi custom field được lưu ở một dòng, nên bạn sẽ cần gộp các dòng đó lại nếu muốn truy vấn tới tất cả chúng.

SELECT * from wp_posts 
INNER JOIN wp_postmeta m1 on m1.post_id = wp_posts.ID AND m1.meta_key = "hcf_price" 
INNER JOIN wp_postmeta m2 on m2.post_id = wp_posts.ID AND m2.meta_key = "hcf_author" 
Where wp_posts.ID = 1

WordPress ghi nhận các cột meta_key, do vậy tốc độ truy vấn sẽ không quá chậm trừ khi bạn có một lượng lớn các dòng (hàng trăm hoặc hàng ngàn dòng). Hầu hết các website sử dụng rất nhiều custom field để tạo các bộ lọc hoặc tạo chức năng tìm kiếm theo giá trị của custom fields. Vì vậy, các truy vấn sẽ như sau:

SELECT * from wp_posts 
INNER JOIN wp_postmeta m1 on m1.post_id = wp_posts.ID AND m1.meta_key = "hcf_price" 
INNER JOIN wp_postmeta m2 on m2.post_id = wp_posts.ID AND m2.meta_key = "hcf_author" 
WHERE m1.meta_value < 100 and m2.author = "metabox"

Lúc này, có một vấn đề lớn xảy ra đó là WordPress không ghi nhận meta_value. Điều đó có nghĩa là các truy vấn dựa trên meta_value sẽ rất chậm. Ngay cả như vậy, bạn cũng không thể khắc phục nó vì meta_value là lặp, và bạn không thể quyết định cấu trúc của nó.

Tóm lại, custom field không được tạo ra để dành cho các truy vấn đâu.

Rác trong database

Mỗi plugin có thể thêm một lượng custom field không giới hạn vào database của bạn. Database từ các custom field sẽ không thể xóa ngay cả khi bạn bỏ cài đặt plugin đó. Một ngày nào đó, khi bạn nhìn lại vào database, bạn sẽ không thể biết được đâu là custom field bạn đã sử dụng, đâu là cái bỏ đi.

Giải pháp

Bạn không thể bỏ WordPress đi chỉ vì những điểm yếu của bảng meta. Hơn nữa, chúng ta cũng không thể nào bỏ qua các điểm mạnh mà thực thế là rất hữu ích của WordPress được. Vấn đề của nó chỉ nằm ở chỗ truy vấn dữ liệu mà thôi. Vì vậy, bạn chỉ cần xử lý vấn đề này thôi là được.

Đặt bảng dạng nằm ngang

Nếu bảng dọc khiến cho chúng ta phải gộp rất nhiều dòng lại với nhau và khó để ghi nhận dữ liệu, thì hãy thử chuyển bảng đó sang dạng ngang. Mỗi custom field sẽ được đặt vào một cột riêng theo thể loại riêng và ghi nhận một kiểu riêng. Sau đó, hook sâu vào để chỉnh sửa các câu truy vấn.

Lưu ý: nếu bạn đang dùng plugin Meta Box, bạn sẽ có sẵn MB Custom Table làm việc đó cho bạn rồi.

Thực tế là cách làm này khá là hiệu quả. Nếu theo cách cũ, bạn có thể sẽ có một số lượng lớn các bảng và cần cập nhật lại cấu trúc của nó mỗi khi có một custom field được thêm vào. Cách cũ sẽ buộc các đối tượng phải có chung một cấu trúc như nhau. Do đó, các custom file của các đối tượng khác nhau (như là Product, Post, Hotel, …) sẽ bị gộp lại và chất thành một đống lẫn lộn, rối tung.

Chia bảng meta ra thành nhiều bảng nhỏ

Thay vì xử lý các truy vấn, chúng ta sẽ chia nhỏ các bảng ra. Bạn có thể thu thập tất cả các custom field thường hay đi cùng nhau, rồi cho chúng vào chung một bảng. Việc gộp lại này khá là hiệu quả. Bạn cũng có thể giới hạn tối đa số lượng dòng trong mỗi bảng nữa. Khi số lượng này đạt đến ngưỡng, một bảng mới lại được tạo ra. Như vậy, bạn sẽ có rất nhiều bảng meta. Ví dụ như wp_postmeta_1, wp_postmeta_2, wp_postmeta_3, …

Khi thực hiện các truy vấn, bạn có thể hook vào một filter và tạo một truy vấn MySQL để thay đổi lệnh MySQL. Bạn cũng có thể dựa trên tên của custom field để nhận dạng tên của các bảng mà bạn truy vấn tới.

Mặc dù cả hai cách này đều can thiệp trực tiếp vào database, nhưng chúng vẫn rất khó để thực hiện và mang đến rất nhiều rủi ro. Đồng thời, chúng không mang lại hiệu quả thực sự rõ rệt.

Cache

Cache là một cách rất hiệu quả và có hiệu quả tức thì luôn trong trường hợp này. Có rất nhiều chiến lược khác nhau cho cache, bạn có thể tìm hiểu thêm về cache ở bài viết này. Nói đơn giản thì chúng sẽ giúp chúng ta hạn chế việc truy vấn đến database, cache các truy vấn hay thậm chí là cache toàn bộ website ở dạng static (tĩnh). Bạn sẽ không cần phải quan tâm đến việc liệu các truy vấn sẽ chậm hay nhanh nữa. Nếu nó quá chậm, thì có nghĩa là có quá ít người dùng truy vấn đến dữ liệu đó.

Tuy nhiên, trong vẫn có một số trường hợp xấu sẽ xảy ra khi mà có nhiều loại request khác nhau từ người dùng, cập nhật dữ liệu hoặc là cache của bạn có vòng đời ngắn, hay số lượng truy vấn đến database rất lớn. Nhưng đừng lo, chúng ta có một giải pháp khác như dưới đây nữa.

Sử dụng giải pháp của bên thứ ba

Bên thứ ba sẽ đứng giữa bạn và các yêu cầu của người dùng để xử lý các request đó. Bạn chỉ cần lo phần nguồn dữ liệu mà thôi. Bạn sẽ không phải lo lắng đến vấn đề cấu trúc dữ liệu của bạn khổng lồ cỡ nào nữa. Nó sẽ có một cấu trúc mới và dễ dàng được truy vấn hơn.

Có một số giải pháp khác nữa mà bạn có thể tham khảo như là ElasticSearch, Redis, hoặc là Algolia.com. Với các giải pháp này, bạn có thể index dữ liệu bằng cấu trúc mới để hỗ trợ việc truy vấn tốc độ nhanh hơn.

Lời kết

Đến đây, chúng ta đã tìm hiểu khá cụ thể về cách mà WordPress xây dựng hệ thống database cho website của bạn rồi. Nhờ vào các bảng meta, WordPress có thể mở rộng thêm khả năng cũng như là hỗ trợ được nhiều loại đối tượng hơn. Song hành với đó là vấn đề về hiệu suất xử lý dữ liệu. Tuy nhiên, với những ưu điểm riêng của hệ thống này, chúng ta vẫn chấp nhận phần nhược điểm của nó, đồng thời phải tìm kiếm thêm các giải pháp khác để cải thiện các nhược điểm này mà thôi. Trong số đó, có một số cách như là chuyển đổi bảng từ dọc sang ngang, chia bảng, hay cache lại bảng dữ liệu là những cách đơn giản nhất và hiệu quả mà bạn nên thử.

Để lại 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 *