Hiểu về mô hình dữ liệu EAV và khi nào sử dụng nó - oPhamThiDao/Devops GitHub Wiki
Một vấn đề mà nhiều nhà phát triển gặp phải khi xác định và phân tích các yêu cầu dữ liệu là tình huống mà một số thuộc tính khác nhau có thể được sử dụng để mô tả một đối tượng, nhưng chỉ có một số thuộc tính thực sự áp dụng cho từng đối tượng.
Một tùy chọn là tạo một bảng với một cột đại diện cho từng thuộc tính; điều này phù hợp với các đối tượng có một số thuộc tính cố định, trong đó tất cả hoặc hầu hết các thuộc tính đều có giá trị cho hầu hết các đối tượng. Tuy nhiên, trong trường hợp mình đưa ra ban đầu, nó sẽ kết thúc với các bản ghi trong đó phần lớn các cột sẽ trống vì các thuộc tính có thể không xác định hoặc không thể áp dụng được.
Để giải quyết vấn đề trên, bạn có thể áp dụng mô hình EAV (Entity, Attribute, Value - Thực thể, Thuộc tính, Giá trị). Mô hình này còn được gọi dưới một số tên thay thế bao gồm mô hình 'object-attribute-value' và 'open schema'.
Trong mô hình dữ liệu EAV, chỉ các giá trị không trống được lưu trữ trong cơ sở dữ liệu, trong đó mỗi cặp attribute-value (hoặc key-value) mô tả một thuộc tính của một thực thể nhất định. Các bảng EAV thường được mô tả là 'long và skinny' trong đó 'long' đề cập đến nhiều hàng mô tả thực thể và 'skinny' đề cập đến số lượng nhỏ các cột được sử dụng.
Trong bài viết này, mình sẽ giải thích về mô hình EAV và cách triển khai của nó, đồng thời hiển thị các ứng dụng trong thế giới thực - bao gồm cả việc xem xét cách Magento sử dụng mô hình này.
Đầu tiên hãy xem qua các lưu ý của EAV:
-
Các thuộc tính đối tượng được lưu trữ trong một bảng có ba cột: thực thể, thuộc tính và giá trị. Đối tượng đại diện cho mục dữ liệu đang được mô tả, chẳng hạn như một sản phẩm hoặc một chiếc ô tô.
-
Thuộc tính đại diện cho dữ liệu mô tả một thực thể, chẳng hạn như một sản phẩm sẽ có giá, trọng lượng và nhiều đặc điểm khác.
-
Giá trị là giá trị của thuộc tính đó, ví dụ: sản phẩm có thể có giá thuộc tính là 9,99$. Ngoài ra, các giá trị có thể được tách biệt dựa trên kiểu dữ liệu, vì vậy sẽ có các bảng EAV riêng biệt cho string, integer, date, long text. Việc phân chia các loại được thực hiện để giúp hỗ trợ lập chỉ mục và cho phép cơ sở dữ liệu thực hiện kiểm tra xác thực loại nếu có thể.
Sự thưa thớt của các thuộc tính
Trong toán học và khoa học máy tính, nếu một đối tượng chỉ có một vài thuộc tính từ một số lớn tiềm năng, mình sẽ gọi đó là 'sparse matrix - ma trận thưa thớt'. Khi nói về mô hình EAV, mình sử dụng thuật ngữ 'sparse - thưa thớt' để mô tả các thuộc tính mà hầu hết không có giá trị.
Để minh họa điều này, hãy xem một biên lai từ một siêu thị. Siêu thị có hàng nghìn sản phẩm trong kho, với những sản phẩm mới được giới thiệu hàng ngày và những sản phẩm khác bị rút khỏi bán.
Khi một khách hàng mua năm sản phẩm, biên lai chỉ liệt kê chi tiết các mặt hàng đã thực sự mua - một sản phẩm trên mỗi hàng. Biên lai không liệt kê mọi sản phẩm trong cửa hàng mà khách hàng có thể đã mua, vì vậy có thể nói rằng biên nhận của khách hàng rất thưa thớt.
Theo thuật ngữ cơ sở dữ liệu, thực thể là biên lai bán hàng, với thông tin như id giao dịch, ngày và giờ, vị trí cửa hàng, v.v. Mỗi dòng chi tiết trong biên lai tương ứng với một bản ghi trong bảng dòng bán hàng và lưu trữ một thuộc tính cộng với một hoặc nhiều các giá trị.
Trong trường hợp này, một thuộc tính là một sản phẩm được mua bởi khách hàng. Các giá trị là số lượng, đơn giá, chiết khấu và tổng giá.
Ví dụ trên minh họa sự thưa thớt của các thuộc tính (khách hàng chỉ mua một số sản phẩm có sẵn) và giới thiệu cho chúng ta một thuật ngữ mới: mô hình hóa hàng. Bảng được mô hình hóa theo hàng trong đó chuỗi dữ kiện mô tả một thực thể được ghi lại thành nhiều hàng. Mọi tập hợp dữ kiện mới được lưu trữ trong cơ sở dữ liệu dưới dạng hàng bổ sung chứ không phải cột bổ sung.
Mô hình hóa hàng là một kỹ thuật mô hình hóa dữ liệu tiêu chuẩn trong thiết kế cơ sở dữ liệu. Nó chỉ nên được sử dụng khi đáp ứng hai điều kiện sau:
- Dữ liệu cho một thực thể cụ thể là thưa thớt
- Dữ liệu dễ bị thay đổi
Mô hình hàng không phù hợp khi không tồn tại sự thưa thớt và không ổn định, trong trường hợp này nên sử dụng mô hình cột truyền thống.
Ví dụ về row modelling
Trong ví dụ này, chúng ta có ba thực thể: Sản phẩm, Khách hàng và Hóa đơn. Cả Sản phẩm và Khách hàng đều là bảng quan hệ tiêu chuẩn.
Như đã đề cập trước đó trong bài viết này, có hai điều kiện cần được đáp ứng để mô hình hàng trở thành một lựa chọn tốt; dữ liệu cho một thực thể cụ thể là thưa thớt và nó dễ bị thay đổi
Biết rằng các sản phẩm liên tục biến động với việc mới được giới thiệu và cũ bị thu hồi. Đồng thời, bảng hóa đơn không thể có một cột cho từng sản phẩm vì điều này sẽ không thực tế.
Bảng hóa đơn bao gồm các thông tin chính về sự kiện bán hàng; khách hàng, ngày giờ và id hóa đơn. Sau đó, mỗi hóa đơn được mô tả bằng các hàng được ghi trong bảng bill_lines. Mỗi hàng chỉ định sản phẩm nào đã được mua, giá mỗi đơn vị và số lượng.
EAV vs row modelling
Thiết kế Entity-Attribute-Value là sự tổng quát hóa của mô hình hóa hàng. Nó có nghĩa là tất cả các loại dữ kiện được ghi lại trong một bảng duy nhất trên toàn bộ cơ sở dữ liệu, trong đó một bảng được mô hình hóa theo hàng là đồng nhất về các dữ kiện mà nó mô tả. Hơn nữa, kiểu dữ liệu của cột giá trị trong bảng được mô hình hóa theo hàng được xác định trước, trong khi trong bảng EAV, kiểu dữ liệu của giá trị phụ thuộc vào thuộc tính được ghi trong một hàng cụ thể.
Có thể khó để chọn cách tiếp cận tốt nhất cho dữ liệu mô hình hóa, nhưng như một hướng dẫn, bạn sẽ cân nhắc việc lập mô hình EAV trên mô hình hàng khi:
-
Các thuộc tính riêng lẻ khác nhau về kiểu dữ liệu được ghi (Có / Không, giá trị số, chuỗi). Nó làm cho việc lưu trữ các giá trị thuộc tính trong một bảng trở nên khó khăn khi sử dụng mô hình hàng.
-
Nhiều danh mục dữ liệu cần được thể hiện và số lượng của chúng có thể dao động. Đồng thời các danh mục có số lượng trường hợp rất nhỏ, ngay cả khi các thuộc tính không thưa thớt. Sử dụng mô hình thông thường trong trường hợp như vậy có nghĩa là hàng trăm bảng với rất ít hàng.
-
Trong một số loại môi trường nhất định, nơi các danh mục/lớp cần được tạo nhanh chóng và một số lớp thường bị loại bỏ trong các chu kỳ tạo mẫu tiếp theo.
-
Trường hợp có các danh mục được phân loại là kết hợp, nghĩa là một số thuộc tính của lớp không phải là phụ tùng và các thuộc tính khác rất thưa thớt. Trong tình huống này, các thuộc tính không thưa thớt được lưu trữ trong bảng thông thường, trong khi các thuộc tính thưa thớt được lưu trữ ở định dạng EAV hoặc theo mô hình hàng. Các lớp thường gặp trong ứng dụng cơ sở dữ liệu kinh doanh, trong đó mô tả sản phẩm phụ thuộc vào danh mục sản phẩm, nhưng tất cả các sản phẩm sẽ chia sẻ các thuộc tính như đơn vị đóng gói và giá mỗi mặt hàng. Lưu ý rằng nếu chỉ có một hoặc hai lớp kết hợp, thiết kế EAV có thể không đáng giá.
Representing entities, attributes và values
Representing Entities
Thực thể có thể là bất kỳ mặt hàng nào, cho đến nay chúng ta đã thấy các ví dụ trong đó thực thể là một sự kiện bán hàng, một người bán và một sản phẩm. Các thực thể trong EAV được quản lý thông qua bảng Đối tượng nắm bắt các thông tin chung về từng mục, chẳng hạn như tên, mô tả, v.v. Bảng Đối tượng phải có mã định danh duy nhất cho mỗi thực thể và mã này thường được tạo tự động. Sau đó, mã định danh được sử dụng trên cơ sở dữ liệu như một khóa ngoại.
Sử dụng mô hình EAV không ngăn chúng tôi sử dụng các bảng thông thường để nắm bắt các chi tiết bổ sung cho các đối tượng riêng lẻ. Người ta thường sử dụng các phương pháp tiếp cận mô hình hóa cơ sở dữ liệu quan hệ truyền thống và mô hình hóa EAV trong cùng một lược đồ cơ sở dữ liệu.
Representing Attributes
Các thuộc tính được lưu trữ trong một bảng thuộc tính chuyên dụng. Khóa chính của bảng này được sử dụng làm tham chiếu trên cơ sở dữ liệu. Bảng thuộc tính thường được bổ sung với nhiều bảng siêu dữ liệu mô tả chi tiết hơn một thuộc tính. Thông tin siêu dữ liệu này thường được sử dụng để tự động tạo giao diện người dùng để duyệt và chỉnh sửa dữ liệu. Các bảng siêu dữ liệu có thể chứa một số loại thông tin sau:
-
Validation: Siêu dữ liệu xác thực bao gồm kiểu dữ liệu của một thuộc tính, giá trị mặc định, giới hạn một số giá trị có thể có và liệu giá trị có thể rỗng hay không.
-
Presentation: Xác định cách thuộc tính được trình bày cho người dùng, cho dù đó là vùng văn bản, trình đơn thả xuống hay tập hợp các radio button radio hay check boxes.
-
Grouping: Các thuộc tính chủ yếu được trình bày theo nhóm cho người dùng. Siêu dữ liệu nhóm xác định thứ tự hiển thị thuộc tính, số lượng thuộc tính được trình bày và loại phông chữ hoặc màu sắc được sử dụng.
-
Range of normal values: Trong một số trường hợp, phạm vi giá trị bình thường cũng được lưu trữ. Chúng có thể khác nhau tùy theo giới tính, độ tuổi, v.v.
Representing Values
Giải pháp đơn giản nhất để biểu diễn dữ liệu trong mô hình EAV là lưu trữ nó dưới dạng chuỗi. Tuy nhiên, cách tiếp cận này tương đối kém hiệu quả vì nó yêu cầu chuyển đổi kiểu dữ liệu khi thực hiện bất kỳ điều gì với các giá trị. Ngoài ra, các chỉ mục trên các giá trị được lưu trữ dưới dạng chuỗi không cho phép tìm kiếm phạm vi được tối ưu hóa cho các loại ngày và số; đây là một vấn đề phổ biến khi làm việc với dữ liệu cặp khóa-giá trị của các kiểu dữ liệu hỗn hợp.
Để cải thiện tình trạng này, mô hình EAV sử dụng các bảng riêng biệt cho từng loại dữ liệu. Siêu dữ liệu thuộc tính xác định loại dữ liệu chính xác và sau đó là bảng EAV nơi dữ liệu được lưu trữ. Cách tiếp cận này hiệu quả hơn nhiều vì nó cho phép lưu siêu dữ liệu vào bộ nhớ đệm cho một tập hợp các thuộc tính nhất định trong một biểu mẫu trước khi truy cập dữ liệu.
Một nhược điểm lớn của giải pháp này là khi kiểu dữ liệu của một thuộc tính cần thay đổi. Điều này đòi hỏi phải gán lại dữ liệu từ bảng này sang bảng khác, điều này rất bất tiện và có thể được thực hiện bằng các thủ tục được lưu trữ.
Nói chung, các giá trị trống hoặc không áp dụng cho thực thể này không được lưu trữ trong mô hình EAV. Tuy nhiên, trong một số trường hợp, cần phải ghi lại lý do thiếu giá trị. Trong những trường hợp như vậy, giải pháp là thêm một cột mã giá trị bị thiếu vào bảng, cột này chỉ không null khi cột giá trị là null. Mã này sau đó được sử dụng để tra cứu danh sách các giải thích dạng văn bản.
An EAV example
Việc triển khai EAV đơn giản nhất có thể chỉ có ba bảng: entity, attribute và value. Ví dụ về thiết lập này được hiển thị ở đây:
Tuy nhiên, trong quá trình triển khai như vậy, có thể sẽ mất thông tin siêu dữ liệu và tất cả các giá trị được lưu trữ dưới dạng varchar, bất kể kiểu dữ liệu của chúng là gì. Là một biến thể của cách tiếp cận này, chúng ta có thể thực hiện một cách khác là cách tiếp cận được định kiểu mạnh trong đó giá trị của kiểu dữ liệu đã cho được ghi lại trong một bảng cụ thể cho kiểu dữ liệu đó. Một lược đồ ví dụ được hiển thị bên dưới và bao gồm bộ nhớ siêu dữ liệu mà đã đề cập trước đó.
How Magento uses the EAV model
Trong cộng đồng mã nguồn mở và php, một trong những cách triển khai nổi tiếng nhất của mô hình EAV là trong Magento, nền tảng thương mại điện tử. Chúng ta hãy bắt đầu bằng cách xem qua lược đồ cơ sở dữ liệu Magento. Mặc dù điều này có vẻ phức tạp lúc đầu, nhưng chúng ta sẽ xem xét nó theo từng giai đoạn.
Như đã đề cập trước đây một thực thể có thể là bất kỳ mục hoặc sự kiện nào. Trong Magento có nhiều thực thể, ví dụ: khách hàng, đơn đặt hàng, hóa đơn và sản phẩm. Với mục đích của bài viết này, tôi sẽ sử dụng thực thể sản phẩm để giải thích việc triển khai EAV. Bảng chính cho các sản phẩm là danh mục_sản phẩm_danh mục. Tuy nhiên, bạn có thể ngạc nhiên rằng nó chỉ chứa một vài thông tin, chẳng hạn như loại thực thể, SKU và thời điểm sản phẩm được tạo ra.
Để tạo toàn bộ bản ghi sản phẩm, chúng ta cần tìm các thuộc tính của nó và sau đó tìm giá trị cho mỗi thuộc tính. Trong catalog_product_entity, bạn sẽ tìm thấy cột entity_type_id. Điều này được sử dụng trên toàn bộ cơ sở dữ liệu làm mã định danh loại thực thể. Dựa trên loại thực thể, chúng tôi có thể tìm thuộc tính nào được gán cho sản phẩm bằng cách xem trong eav_attribute.
Bảng này ghi lại tất cả các thuộc tính cho tất cả các thực thể trong Magento. Nó cũng có thông tin siêu dữ liệu cho mỗi bản ghi, chẳng hạn như kiểu dữ liệu, chi tiết giao diện người dùng, v.v. Đối với sản phẩm, id loại thực thể được đặt thành 4 (các loại được liệt kê trong bảng eav_entity_type). Chọn tất cả các thuộc tính được chỉ định cho các sản phẩm, chúng tôi chỉ cần thực hiện:
SELECT * FROM eav_attribute WHERE entity_type_id = 4;
Tên của một thuộc tính được ghi lại dưới dạng thuộc tính_mã; từ thông tin siêu dữ liệu, một cột quan trọng là backend_type. Điều này cho biết kiểu dữ liệu của thuộc tính là gì và nơi lưu trữ các giá trị cho thuộc tính. Magento cho phép các kiểu dữ liệu sau:
- static
- datetime
- decimal
- int
- text
- varchar
Như đã đề cập trước đây, các giá trị có thể được lưu trữ trong nhiều bảng dựa trên loại của chúng. Để kiểm tra một thuộc tính cụ thể, chúng ta có thể sử dụng một truy vấn như sau:
SELECT * FROM eav_attribute WHERE entity_type_id = 4 AND attribute_code = 'name';
Sau khi chạy truy vấn trên, chúng ta có thể thấy thuộc tính 'name' có kiểu dữ liệu là varchar. Các giá trị thuộc tính sản phẩm được lưu trữ trên một số bảng: catalog_product_entity_datetime, catalog_product_entity_decimal, catalog_product_entity_int, catalog_product_entity_text, catalog_product_entity_varchar. Các tên bảng này minh họa cách các kiểu dữ liệu khác nhau được lưu trữ trong mô hình EAV.
Để có được danh sách tất cả các sản phẩm và tên của chúng, chúng ta có thể sử dụng một truy vấn như sau:
SELECT cpe.entity_id, value AS name FROM catalog_product_entity cpe
INNER JOIN eav_attribute ea ON cpe.entity_type_id = ea.entity_type_id
INNER JOIN catalog_product_entity_varchar cpev ON ea.attribute_id = cpev.attribute_id AND cpe.entity_id = cpev.entity_id
WHERE ea.attribute_code = 'name'
Khái niệm này đơn giản khi bạn biết bắt đầu từ đâu và cách tìm bảng tiếp theo trong hệ thống phân cấp. Tất cả các thực thể khác đều tuân theo cùng một nguyên tắc: bạn tìm id loại thực thể cho một đối tượng mà bạn quan tâm, sau đó bạn lấy tất cả các thuộc tính từ eav_attribute dựa trên nó và cuối cùng chọn giá trị cho từng thuộc tính từ các bảng khác nhau dựa trên loại thuộc tính.
Advantages and disadvantages of the EAV model
Ưu điểm chính của việc sử dụng EAV là tính linh hoạt của nó. Thuộc tính giữ bảng mô tả một thực thể không bị giới hạn ở một số cột cụ thể, có nghĩa là nó không yêu cầu thiết kế lại giản đồ mỗi khi thuộc tính mới cần được giới thiệu. Số lượng thuộc tính có thể tăng theo chiều dọc (bản ghi bảng mới cho mọi tham số mới) khi cơ sở dữ liệu phát triển mà không cần thay đổi cấu trúc.
Thực tế là EAV chỉ xử lý các thuộc tính không trống có nghĩa là không cần dành thêm không gian lưu trữ cho các thuộc tính có giá trị là rỗng. Điều này làm cho mô hình EAV khá hiệu quả về không gian.
Định dạng dữ liệu vật lý rất rõ ràng và tương tự như XML, cho phép dữ liệu được ánh xạ dễ dàng sang định dạng XML; nó chỉ yêu cầu thay thế tên thuộc tính bằng các thẻ thuộc tính bắt đầu và thuộc tính kết thúc.
Mô hình EAV là tuyệt vời cho các ứng dụng phát triển nhanh chóng vì nó bảo vệ chúng ta trước những hậu quả của sự thay đổi liên tục. Chúng ta có thể ghi lại dữ liệu mới của bất kỳ cấu trúc nào một cách đơn giản mà không cần phải sửa đổi lược đồ cơ sở dữ liệu.
Khi xem xét EAV, điều quan trọng là phải xác định xem dữ liệu có thưa thớt và nhiều hay không vì sự phức tạp của thiết kế EAV vượt quá lợi thế của nó khi được sử dụng cho tập dữ liệu không phù hợp. Sẽ thích hợp hơn nếu chọn các bảng thông thường cho các lược đồ tương đối tĩnh và / hoặc đơn giản.
Một nhược điểm lớn của EAV là hiệu quả thấp hơn khi truy xuất dữ liệu hàng loạt so với cấu trúc thông thường. Trong mô hình EAV, dữ liệu thực thể bị phân mảnh hơn và do đó, việc chọn toàn bộ bản ghi thực thể yêu cầu nhiều phép nối bảng. Hơn nữa, khi làm việc với khối lượng lớn dữ liệu EAV, có thể cần phải chuyển đổi tạm thời hoặc vĩnh viễn giữa biểu diễn dạng cột và hàng / EAV theo mô hình hóa của cùng một bộ dữ liệu. Hoạt động này có thể dễ xảy ra lỗi và tốn nhiều CPU.
Một hạn chế khác của EAV là thực tế là chúng ta cần thêm logic để hoàn thành các nhiệm vụ sẽ được thực hiện tự động bởi các lược đồ thông thường. Tuy nhiên, các công cụ EAV hiện có có thể được triển khai để giảm chi phí chung của việc này.
Cuối cùng, việc hiểu mô hình EAV đòi hỏi thời gian. Nó có một đường cong học tập xác định, vì vậy các nhà phát triển cơ sở có thể gặp khó khăn khi làm việc với mô hình này, trước khi họ có thể thực sự hiểu khái niệm.
Conclusion
Nên xem xét các điều kiện sau để áp dụng Entity Attribute Value cho ứng dụng của bạn:
-
Dữ liệu thưa thớt và không đồng nhất, với nhiều thuộc tính có thể áp dụng cho một thực thể và các thuộc tính mới thường được đưa vào. Số lượng các lớp rất lớn, với các lớp có rất nhiều cá thể, ngay cả khi các thuộc tính không thưa thớt.
-
Có rất nhiều lớp lai, sở hữu cả thuộc tính thưa thớt và không thưa thớt. Thông thường, không phải tất cả các lớp trong dữ liệu sẽ đáp ứng các yêu cầu đối với mô hình EAV.
-
Trong quá trình sản xuất, các lược đồ có xu hướng được kết hợp, bao gồm các phương pháp tiếp cận quan hệ thông thường, EAV hoặc kết hợp nếu thích hợp. Tuy nhiên, mô hình EAV yêu cầu giới thiệu siêu dữ liệu để thu thập dữ liệu mô hình logic cho EAV. Mình thấy rằng trong Magento, điều này được sử dụng rất hiệu quả khi các sản phẩm khác nhau sẽ có các thuộc tính rất khác nhau; một minh họa đẹp về nơi mà mô hình này có thể được áp dụng rất hiệu quả.
Bài đăng này hy vọng đã cho bạn thấy mô hình EAV là gì và cách thức, và quan trọng hơn là khi nào, sử dụng nó!