EAV - nó thực sự tồi tệ trong tất cả các kịch bản?


65

Tôi đang suy nghĩ sử dụng mô hình giá trị thuộc tính thực thể (EAV) cho một số nội dung trong một trong các dự án, nhưng tất cả các câu hỏi về nó trong Stack Overflow đều kết thúc để trả lời gọi EAV là mô hình chống.

Nhưng tôi tự hỏi nếu nó là sai trong tất cả các trường hợp.

Giả sử thực thể sản phẩm cửa hàng, nó có các tính năng phổ biến, chẳng hạn như tên, mô tả, hình ảnh và giá cả, tham gia logic nhiều nơi và có (bán) các tính năng độc đáo, như đồng hồ và bóng bãi biển sẽ được mô tả bởi các khía cạnh hoàn toàn khác nhau. Vì vậy, tôi nghĩ rằng EAV sẽ phù hợp để lưu trữ các tính năng (bán) độc đáo đó.

Tất cả điều này là giả sử, để hiển thị danh sách sản phẩm, nó có đủ thông tin trong bảng sản phẩm (có nghĩa là không có EAV nào tham gia) và chỉ khi hiển thị một sản phẩm / so sánh tối đa 5 sản phẩm / v.v. dữ liệu được lưu bằng EAV được sử dụng.

Tôi đã thấy cách tiếp cận như vậy trong thương mại Magento và nó khá phổ biến, vậy có trường hợp nào khi EAV hợp lý không?



Để biết ví dụ về mẫu EAV hoạt động rất tốt, hãy xem cơ sở dữ liệu Datomic. Nó lưu trữ mọi thứ trong mẫu EAVT (T là "dấu thời gian", thực sự giống như một id giao dịch). [Tài liệu lập chỉ mục] của họ (docs.datomic.com/indexes.html) dường như hiển thị nó tốt nhất. Để biết ví dụ về EAV hoạt động khủng khiếp, xem Wordpress .
Dan Ross

Câu trả lời:


81

https://web.archive.org/web/20140831134758/http://www.dbforums.com/database-con chấp nhận

EAV cung cấp sự linh hoạt cho nhà phát triển để xác định lược đồ khi cần thiết và điều này tốt trong một số trường hợp.

Mặt khác, nó thực hiện rất kém trong trường hợp truy vấn không xác định và có thể hỗ trợ các thực tiễn xấu khác.

Nói cách khác, EAV cung cấp cho bạn đủ dây để treo mình và trong ngành này, mọi thứ nên được thiết kế ở mức độ phức tạp thấp nhất bởi vì anh chàng thay thế bạn trong dự án có thể sẽ là một thằng ngốc.


32
Yêu câu cuối cùng.
Zohar Peled

2
Liên kết thối. Có một phiên bản lưu trữ ở đâu đó?
tự đại diện

1
Đừng theo liên kết. Trang tải chậm và không hữu ích. Ngoài ra, các diễn đàn kiểu cũ như thế. Sử dụng ngăn xếp tràn thay thế! Upvote câu trả lời tốt / hữu ích và đẩy xuống thùng rác.
Jess

29

Tóm lại, EAV rất hữu ích khi danh sách các thuộc tính của bạn thường xuyên tăng hoặc khi nó lớn đến mức hầu hết các hàng sẽ chứa đầy chủ yếu là NULL nếu bạn tạo mỗi thuộc tính một cột. Nó trở thành một mô hình chống khi được sử dụng bên ngoài bối cảnh đó.


16
Tôi sẽ thay thế "thường xuyên" bằng "cần thay đổi khả năng thay đổi trong thời gian chạy".
Doc Brown

3
Chúng ta có thể rút ngắn hơn nữa Doc Brown bằng cách sử dụng từ "động" được hiểu khá rõ - EAV rất hữu ích khi danh sách các thuộc tính của bạn có thể thay đổi linh hoạt.
Alexander Mills

Thậm chí xa hơn là "khi các thuộc tính của bạn có thể thay đổi" - "động" là hơi dư thừa trong bối cảnh này :)
Wranorn

1
Có nhất thiết phải hữu ích hơn là, có hình thức thay đổi một thuộc tính thực hiện một CREATE TABLEcho thuộc tính mới không?
Damian Yerrick

@DamianYerrick cách tiếp cận thú vị. Bạn đã sử dụng điều này trong sản xuất?
đào

21

Giả sử thực thể sản phẩm cửa hàng, nó có các tính năng phổ biến, như tên, mô tả, hình ảnh, giá cả, v.v., tham gia logic nhiều nơi và có (bán) các tính năng độc đáo, như đồng hồ và bóng bãi biển sẽ được mô tả bởi các khía cạnh hoàn toàn khác nhau . Vì vậy, tôi nghĩ rằng EAV sẽ phù hợp để lưu trữ các tính năng (bán) độc đáo đó?

Sử dụng cấu trúc EAV cho một số ý nghĩa là sự đánh đổi.

Bạn đang giao dịch với 'ít không gian hơn cho hàng vì bạn không có 100 cột null' chống lại 'các truy vấn và mô hình phức tạp hơn'.

Có EAV thường có nghĩa là giá trị là một chuỗi mà người ta có thể nhét bất kỳ dữ liệu nào vào. Điều này sau đó có ý nghĩa về kiểm tra tính hợp lệ và ràng buộc. Hãy xem xét tình huống bạn đã đặt số lượng pin được sử dụng như một cái gì đó trong bảng EAV. Bạn muốn tìm một đèn pin sử dụng pin cỡ C, nhưng ít hơn 4 trong số chúng.

select P.sku
from
  products P
  attrib Ab on (P.sku = Ab.sku and Ab.key = "batteries")
  attrib Ac on (P.sku = Ac.sku and Ac.key = "count")
where
  cast(Ac.value as int) < 4
  and Ab.value = 'C'
  ...

Điều cần nhận ra ở đây là bạn không thể sử dụng chỉ mục một cách hợp lý trên giá trị. Bạn cũng không thể ngăn ai đó đưa vào thứ gì đó không phải là số nguyên ở đó hoặc số nguyên không hợp lệ (sử dụng pin '-1') vì cột giá trị được sử dụng nhiều lần cho các mục đích khác nhau.

Điều này sau đó có ý nghĩa trong việc cố gắng viết một mô hình cho sản phẩm. Bạn sẽ có những giá trị được gõ tốt ... nhưng bạn cũng sẽ Map<String,String>chỉ ngồi đó với đủ thứ trong đó. Điều này sau đó có ý nghĩa hơn nữa khi tuần tự hóa nó thành XML hoặc Json và sự phức tạp của việc cố gắng xác thực hoặc truy vấn đối với các cấu trúc đó.

Một số lựa chọn thay thế hoặc sửa đổi cho mẫu cần xem xét là thay vì khóa biểu mẫu miễn phí, để có một bảng khác có khóa hợp lệ. Nó có nghĩa là thay vì thực hiện so sánh chuỗi trong cơ sở dữ liệu, bạn đang kiểm tra tính bằng nhau của id khóa ngoài. Thay đổi chính nó được thực hiện tại một điểm. Bạn đã có một bộ khóa được biết đến, điều đó có nghĩa là chúng có thể được thực hiện như một enum.

Bạn cũng có thể có các bảng liên quan có chứa các thuộc tính của một loại sản phẩm cụ thể. Một bộ phận tạp hóa có thể có một bảng khác có một số thuộc tính liên quan đến nó mà vật liệu xây dựng không cần (và ngược lại).

+----------+    +--------+    +---------+
|Grocery   |    |Product |    |BuildMat |
|id (fk)   +--->|id (pk) |<---+id (fk)  |
|expiration|    |desc    |    |material |
|...       |    |img     |    |...      |
+----------+    |price   |    +---------+
                |...     |               
                +--------+               

Có những lúc đặc biệt gọi cho bảng EAV.

Hãy xem xét tình huống mà bạn không chỉ viết một hệ thống kiểm kê cho công ty của bạn, nơi bạn biết mọi sản phẩm và mọi thuộc tính. Bây giờ bạn đang viết một hệ thống hàng tồn kho để bán cho các công ty khác. Bạn không thể biết mọi thuộc tính của mọi sản phẩm - họ sẽ cần xác định chúng.

Một ý tưởng mà đi ra là "chúng tôi sẽ cho khách hàng sửa đổi bảng" và điều này chỉ là xấu (bạn nhận được vào meta-lập trình cho các cấu trúc bảng bởi vì bạn không còn biết gì là ở đâu, họ có thể royally mess lên cấu trúc hoặc bị hỏng ứng dụng, họ đã có quyền truy cập để làm những điều sai trái và ý nghĩa của việc truy cập đó trở nên quan trọng). Có nhiều hơn về đường dẫn này tại MVC4: Làm thế nào để tạo mô hình trong thời gian chạy?

Thay vào đó, bạn tạo giao diện quản trị cho bảng EAV và cho phép sử dụng giao diện đó. Nếu khách hàng muốn tạo một mục nhập cho 'polkadots', nó sẽ đi vào bảng EAV và bạn đã biết cách xử lý vấn đề đó.

Một ví dụ về điều này có thể được nhìn thấy trong mô hình cơ sở dữ liệu cho Redmine, bạn có thể thấy bảng custom_fields và bảng custom_values ​​- đó là những phần của EAV cho phép hệ thống được mở rộng.


Lưu ý rằng nếu bạn thấy toàn bộ cấu trúc bảng của mình trông giống EAV hơn là quan hệ, bạn có thể muốn xem hương vị KV của NoQuery (cassandra, redis, Mongo, ...). Nhận ra rằng những điều này thường đi kèm với sự đánh đổi khác trong thiết kế của họ có thể phù hợp hoặc không phù hợp với những gì bạn đang sử dụng. Tuy nhiên, chúng được thiết kế đặc biệt với mục đích của cấu trúc EAV.

Bạn có thể muốn đọc SQL vs NoQuery cho hệ thống quản lý kho

Theo cách tiếp cận này với cơ sở dữ liệu NoQuery theo định hướng tài liệu (couch, mongo), bạn có thể coi mỗi mục kiểm kê là một tài liệu trên đĩa ... kéo mọi thứ trong một tài liệu trở nên nhanh chóng. Hơn nữa, tài liệu được cấu trúc để bạn có thể rút ra bất kỳ một điều duy nhất nào nhanh chóng. Mặt khác, tìm kiếm tất cả các tài liệu cho những thứ phù hợp với một thuộc tính cụ thể có thể có hiệu suất thấp hơn (so sánh sử dụng 'grep' với tất cả các tệp) ... tất cả đều là một sự đánh đổi.

Một cách tiếp cận khác sẽ là LDAP trong đó người ta sẽ có một cơ sở với tất cả các mục được liên kết của nó, nhưng sau đó cũng sẽ có các lớp đối tượng bổ sung được áp dụng cho nó cho các loại mục khác. (xem Kiểm kê hệ thống bằng LDAP )

Khi bạn đi xuống con đường này, bạn có thể tìm thấy thứ gì đó phù hợp chính xác với những gì bạn đang tìm kiếm ... mặc dù mọi thứ đều đi kèm với một số sự đánh đổi.


10

6 năm sau

Bây giờ JSON trong Postgres đã ở đây, chúng tôi có một tùy chọn khác, cho những ai đang sử dụng Postgres. Nếu bạn chỉ muốn đính kèm một số dữ liệu bổ sung cho một sản phẩm, thì nhu cầu của bạn khá đơn giản. Thí dụ:

CREATE TABLE products (sku VARCHAR(30), shipping_weight REAL, detail JSON);
INSERT INTO products ('beachball', 1.0, '{"colors": ["red", "white"], "diameter": "50cm"}');

SELECT * FROM products;
    sku    | weight |               detail               
-----------+--------+------------------------------------
 beachball |      1 | {"colors": ["red", "white"], "diameter": "50cm"}

Đây là phần giới thiệu mượt mà về JSON trong Postgres: https://www.compose.com/articles/is-postgresql-your-next-json-database/ .

Lưu ý rằng Postgres thực sự lưu trữ JSONB, không phải JSON văn bản thuần túy và nó hỗ trợ các chỉ mục trên các trường bên trong tài liệu / trường JSONB, trong trường hợp bạn phát hiện ra rằng bạn thực sự muốn truy vấn dữ liệu đó.

Ngoài ra, lưu ý rằng các trường trong trường JSONB không thể được sửa đổi riêng lẻ với truy vấn CẬP NHẬT; bạn sẽ phải thay thế toàn bộ nội dung của trường JSONB.

Câu trả lời này có thể không trực tiếp giải quyết câu hỏi, nhưng nó đưa ra một giải pháp thay thế cho mẫu EAV, cần được xem xét bởi bất kỳ ai đang cân nhắc câu hỏi ban đầu.


3
Tôi nghĩ rằng đó là ý tưởng tuyệt vời để gửi giải pháp thay thế. Để giữ cho những người khác theo dõi, MS SQL đã hỗ trợ các cột XML có khả năng lập chỉ mục cho họ trong một thời gian và bắt đầu từ năm 2016, nó có thể làm tương tự với JSON (mặc dù JSON không phải là loại cột gốc trong MS SQL, bạn vẫn có thể lập chỉ mục cho nó ). Mặt khác - từ những gì tôi đọc được, hỗ trợ JSON của Postgres tốt hơn, ví dụ như có vẻ như nó hỗ trợ các chỉ mục trên dữ liệu trong các thuộc tính mảng JSON.
Giedrius

1
"... các trường trong trường JSONB không thể được sửa đổi riêng lẻ bằng truy vấn CẬP NHẬT; bạn sẽ phải thay thế toàn bộ nội dung của trường JSONB." Điều này đã lỗi thời, phải không? Có một jsonb_set()chức năng trong Postgres 9.5 trở lên, chính xác là điều này. (Bài viết bạn liên kết với các liên kết lần lượt đến một bài viết mới hơn thảo luận về các bổ sung tính năng 9.5 .)
Wildcard

7

Thông thường mọi người nhìn theo cách khác nếu bạn đang sử dụng nó cho các bảng tra cứu hoặc các tình huống khác trong đó lợi ích là không phải tạo các bảng cho một hoặc hai giá trị được lưu trữ. Tình huống bạn đang mô tả, về cơ bản bạn đang lưu trữ các thuộc tính vật phẩm, nghe có vẻ hoàn toàn bình thường (và được chuẩn hóa). Mở rộng một bảng để lưu trữ một số lượng các thuộc tính vật phẩm là một ý tưởng tồi.

Đối với trường hợp chung là lưu trữ dữ liệu khác nhau trong một bảng mỏng dài ... Bạn không nên sợ tạo bảng mới nếu bạn cần và chỉ có một hoặc hai bảng mỏng dài sẽ tốt hơn nhiều so với chỉ có một hoặc hai bàn mỡ ngắn.

Điều đó đang được nói, tôi nổi tiếng với việc sử dụng các bảng EAV để đăng nhập. Họ có một số tiện ích tốt.


Vui lòng xác định "bảng gầy" và "bảng béo".
Tulains Córdova

@ TulainsCórdova: Một bảng "gầy" sẽ là một bảng có vài hàng và nhiều cột, trong khi một bảng béo là một bảng có nhiều cột và vài hàng. Một ví dụ sẽ là xây dựng một bảng tra cứu nơi bạn có các thuộc tính để nói, sách. Một bảng chất béo sẽ có một bản ghi cho mỗi cuốn sách, với nhiều cột cho các phần dữ liệu cụ thể, trong khi một bảng mỏng có thể có bốn cột id, book, field_name, field_data. Ưu điểm của thứ nhất là có ít hồ sơ hơn, nhưng điều tiêu cực là một số trường có thể trống và toàn bộ điều khó mở rộng hơn.
Satanicpuppy

@Satanicpuppy Tôi nghĩ rằng định nghĩa gầy / béo của bạn bị lẫn lộn - chúng giống nhau. Bạn có nghĩa là một bảng gầy có vài cột và nhiều hàng?
Charles Wood

1

EAV thay đổi vấn đề về cấu trúc rõ ràng, để nhận thức ngụ ý. Thay vì nói X là một bảng có các cột A và B. Bạn ngụ ý rằng các cột A và B tạo thành bảng X. Đó là sự đảo ngược theo một nghĩa nhưng nhất thiết không phải là ánh xạ một-một. Bạn có thể nói rằng cả A và B đều ánh xạ tới bảng (hoặc loại) X và Y. Điều này có thể quan trọng trong miền liên quan nhiều hơn, nơi bối cảnh quan trọng.

Tôi đã nghiên cứu Datomic, cho kiểu tiếp cận này và tôi nghĩ rằng nó là một hệ thống rất hữu ích và mạnh mẽ với các giới hạn về những gì bạn nên làm với nó (không phải là bạn không thể).

EAV đó sẽ chậm, hoặc "cung cấp cho bạn đủ dây để tự treo cổ" không phải là một tuyên bố mà tôi đồng ý. Thay vào đó, tôi sẽ nhấn mạnh hơn vào các điểm mạnh của EAV và nếu nó phù hợp với không gian vấn đề của bạn, bạn nên xem xét nó.

Kinh nghiệm của tôi là đó là một cách tiếp cận tuyệt vời gần như không bị ràng buộc để mô hình hóa. Cụ thể, trong trường hợp của Datomic, họ áp đặt một ngữ nghĩa được đặt lên trên tất cả mọi thứ. Bất kỳ quyết định mô hình nào mà mô hình hóa một mối quan hệ có thể tự do đi từ một, đến nhiều mà không phải thiết kế lại các cột / bảng. Bạn cũng có thể quay lại miễn là ràng buộc không vi phạm bất biến. Tất cả đều giống nhau dưới mui xe.

Vấn đề với EAV là trong tâm trí tôi thiếu việc triển khai như Datomic. Vì đây là câu hỏi về EAV, tôi không muốn nói về Datomic nhưng đó là một trong những điều mà tôi nghĩ rằng họ đã làm mọi thứ đúng với EAV.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.