Làm thế nào để tạo một cơ sở dữ liệu cho các loại dữ liệu không xác định?


7

Tôi đang trong quá trình thiết kế cơ sở dữ liệu cho một ứng dụng dựa trên PHP / MySql mới.

Vấn đề của tôi là tôi không và không thể đại diện cho những gì nên được lưu trong cơ sở dữ liệu vì nó không giới hạn và thay đổi.

Dưới đây là ví dụ về vấn đề: Ứng dụng sẽ là một trang web mua sắm có nhiều loại sản phẩm, tất cả chúng đều có một số thuộc tính được chia sẻ như titlepricemột số loại có chi tiết cụ thể như expiry datemột isbnsố không có.

Đây chỉ là một ví dụ nhưng tôi thực sự có nhiều loại với nhiều thuộc tính khác nhau.

Tôi có thể tạo một bảng cho từng loại, nhưng những gì tôi có không phải là tất cả các loại có sẵn, nhiều loại vật phẩm không xác định tại thời điểm này.

Đây có phải là cách để giải quyết vấn đề này mà không cần đứng đầu về phía người dùng?


4
vi.wikipedia.org/wiki/Entity từ chối đóng góp giá trị_model là những gì bạn đang tìm kiếm
Philᵀᴹ

1
Tôi có một câu hỏi tương tự được hỏi về Stack Overflow: Làm cách nào để thiết kế cơ sở dữ liệu cho Trường do người dùng xác định? . Bạn có thể quan tâm đến việc kiểm tra thông tin được đăng ở đó. Tôi nghĩ rằng kết quả cuối cùng tôi đi cùng là một bảng cho tất cả các thuộc tính chia sẻ, và sau đó cho phép người dùng thực hiện bảng cho các thuộc tính dữ liệu của nhóm chung được biết đến của các thực thể (ví dụ như Books, Music, vv), và EAV cho các thuộc tính dữ liệu hiếm.
Rachel

Câu trả lời:


10

Không biết các loại dữ liệu âm thanh đối với tôi hơi tanh. Ví dụ của bạn, tất nhiên, tất cả đều được biết đến. Đối với hàng hóa và dịch vụ, việc phân tích và chuẩn hóa cẩn thận là rất quan trọng và tôi nghĩ bạn có thể thoát khỏi mô hình EAV (mà tôi nghĩ sẽ gây ra vấn đề về đạo đức hơn là giải quyết) cho dữ liệu cốt lõi. Phần còn lại có thể được nhồi trong các trường XML hoặc tương tự. Ngoài ra, nếu bạn thực hiện đúng thiết kế của mình, bạn luôn có thể mở rộng thông tin một cách thích hợp. Hãy xem xét ba bảng sau:

CREATE TABLE products (
    id int autoincrement primary key,
    sellprice numeric,
    part_code varchar(10),
    title varchar(32),
    description text
);

CREATE TABLE barcode_type (
    id int autoincrement primary key,
    label varchar(15) not null unique
);

CREATE TABLE make_model (
    id int autoincrement primary key,
    make varchar(15) not null,
    model varchar(15),
    barcode_type int references barcode_type(id),
    barcode varchar(32)
);

Giờ đây, với điều này, bạn có thể gán mã vạch (bao gồm cả ISBN, EAN, UPC, v.v., cho các bộ phận khác nhau, một tổ hợp cho mỗi kiểu / mô hình. Nếu bạn cần hỗ trợ thêm các loại mã vạch, điều này không khó để thêm vào. Nếu những điều này diễn ra tùy thuộc vào nơi bạn đang theo dõi họ. Nếu bạn muốn có giá tạm thời hoặc định giá cho các nhóm khách hàng, bạn cũng có thể thêm điều đó.

Tuy nhiên những gì bạn đang mô tả không có vẻ rất phi cấu trúc. Tôi sẽ đề nghị bắt đầu với một thiết kế tối thiểu và mở rộng khi cần thiết thay vì thiết kế EAV và sau đó hối hận.


9

Có một số chi tiết cụ thể về SQL Server ở đây, nhưng tôi nói chung về EAV của tôi . Nó không phải là ma quỷ mà nó thường được tạo ra, và một số vấn đề lý do điển hình có thể tránh được. Ví dụ: @KookieMonster nói rằng bạn không thể thực thi rằng người dùng không có hai ngày sinh, nhưng điều đó thật dễ dàng:

CREATE TABLE dbo.Users
(
  UserID INT PRIMARY KEY,
  Username NVARCHAR(255) UNIQUE
  --, ...
);

CREATE TABLE dbo.Properties
(
  PropertyID INT PRIMARY KEY,
  Name SYSNAME UNIQUE
  --, ...
);

CREATE TABLE dbo.UserProperties
(
  UserID INT FOREIGN KEY ...,
  PropertyID INT FOREIGN KEY ...,
  DateValue DATE,
  IntValue INT,
  -- ...
  PRIMARY KEY(UserID, PropertyID)
);

(Một lần nữa, đây là cú pháp SQL Server nhưng hy vọng khái niệm này cộng hưởng.)

Nếu logic phức tạp hơn thế (ví dụ: họ có thể có ba số điện thoại nhưng chỉ có một ngày sinh), thì nó sẽ phức tạp hơn một chút, nhưng bạn vẫn có thể thực thi những điều phù hợp với logic kinh doanh của mình bằng cách sử dụng trình kích hoạt, quy trình được lưu trữ, v.v. không biết làm thế nào bất kỳ giải pháp khác sẽ giải quyết vấn đề này tốt hơn trong khi đồng thời không giới thiệu người khác.

Hiệu suất có thể là một vấn đề, tuy nhiên chúng tôi đã giải quyết vấn đề này trong SQL Server 2008+ bằng cách sử dụng các chỉ mục được lọc (đối với các thuộc tính cụ thể) và lười biếng thực hiện các phiên bản không chuẩn hóa của các bảng. Đối với các tập hợp các thuộc tính đang thay đổi chậm, có thể dễ dàng thực hiện các quy trình nền sẽ làm phẳng các bảng sao cho đối với một số hoặc tất cả các sản phẩm bạn có phiên bản dữ liệu được xoay vòng, cụ thể hóa để tránh tất cả các phép nối. Làm thế nào điều đó sẽ hoạt động trong MySQL Tôi không chắc lắm, vì vậy tôi sẽ không cung cấp cú pháp, nhưng có lẽ tôi sẽ viết blog thêm về điều này từ phối cảnh SQL Server ...


1
+1 để hiển thị các mặt tốt của EAV cũng. Đây chắc chắn là một mô hình có thể quản lý được, nhưng như bạn nhận thấy, việc thực thi logic có thể gặp khó khăn (ví dụ như một ngày sinh và 3 số điện thoại). Những người chọn cách này nên làm như vậy để biết nhược điểm ... và ưu!
KookieMonster

@KookieMonster vậy cách khác để làm điều đó là gì? Ba cột số điện thoại và một cột Ngày sinh? Và nếu bạn muốn thêm số điện thoại thứ 4, bạn phải thêm một cột mới? Như tôi đã nói, việc thực thi một số quy tắc nhất định có thể phức tạp nhưng tôi thường sẽ sử dụng lược đồ thay đổi liên tục, API thích ứng vĩnh viễn và bảng mở rộng không ngừng.
Aaron Bertrand

+1 như @KookieMonster đã nói. Điều quan trọng là, IMO, EAV thực sự tuyệt vời cho một số thứ. Chúng tôi sử dụng nó trong một số lĩnh vực của mã LedgerSMB chẳng hạn. Tôi khá chắc chắn rằng nó không phải là nơi thích hợp để bắt đầu với vấn đề này nhưng cuối cùng nó có thể là một phần quan trọng của giải pháp.
Chris Travers

Tôi hết lòng đồng ý.
KookieMonster

7

Không sử dụng MySQL, cơ sở dữ liệu quan hệ không được sử dụng cho giải pháp của loại vấn đề này. Sử dụng một tài liệu hoặc cơ sở dữ liệu NoQuery như MongoDB hoặc có thể là RavenDB trên windows.

Hoặc thay thế sử dụng PostgreSQL. Nếu bạn có một bộ thuộc tính cơ sở, bạn có thể xây dựng tính kế thừa vào các bảng của mình

create table base_items
( id bigint,
title varchar(50),
price money)

sau đó cho các mặt hàng khác, nói sách hoặc thực phẩm

create table book_items 
(isbn varchar(20))
inherits (base_items)

create table food_items (date expiry_date)
inherits(base_items)

làm cho dữ liệu của bạn

insert into base_items (id,item,amount) values
(3,'soap',0.99);

insert into food_items (id,item,expiry,amount) values
(4,'banana','2012-01-01',0.50);

insert into book_items (id,item,isbn,amount) values
(1,'some book','ABC-000-02100',20.99);

insert into book_items (id,item,isbn,amount) values
(2,'some other book','ABC-000-02102',20.99);

select * from base_items;
 id |      item       | amount
----+-----------------+--------
  3 | soap            |  £0.99
  1 | some book       | £20.99
  2 | some other book | £20.99
  4 | banana          |  £0.50


 select * from book_items;
 id |      item       | amount |     isbn
----+-----------------+--------+---------------
  1 | some book       | £20.99 | ABC-000-02100
  2 | some other book | £20.99 | ABC-000-02102


select * from food_items;
 id |  item  | amount |   expiry
----+--------+--------+------------
  4 | banana |  £0.50 | 2012-01-01

5
Đừng chỉ ném một câu như vậy ở đây. Những câu như vậy không được sử dụng để trả lời loại câu hỏi này nhưng để bán một cái gì đó. Sử dụng giải thích trên DBA.SE.
dezso

4
@PaddyCarroll Trong khi tôi không đồng ý về bản chất của câu trả lời, tôi đã không đánh giá thấp điều này. Tôi đã đánh giá thấp vì câu trả lời của bạn quá ngắn. Hãy nhìn xem, thậm chí phản hồi bình luận của bạn cho Chris còn dài hơn câu trả lời của bạn. Vui lòng đặt câu hỏi đó (và bất kỳ lời biện minh nào khác mà bạn có) cho câu trả lời của bạn và tôi sẽ vui lòng đảo ngược phiếu bầu của tôi. Tôi không nghĩ bất cứ ai phản đối các quan điểm khác nhau tại trang web này nhưng chúng tôi phản đối các câu trả lời ít được giải thích và hợp lý hơn.
ypercubeᵀᴹ

3
Bạn có thể đúng, nhưng đối với tôi phải thừa nhận rằng, một vài điểm còn thiếu: tại sao NoQuery, những lợi thế chống lại EAV, siêu kiểu phụ, đề xuất của Chris hoặc các giải pháp khả thi khác (bảng thưa thớt, v.v.)
dezso

4
@PaddyCarroll vui lòng thêm một số chất vào câu trả lời này, hoặc tôi sẽ coi đó là một nhận xét và chuyển đổi nó cho bạn. "Đừng làm điều đó" không phải là một câu trả lời trừ khi nó cũng bao gồm "Làm điều này thay thế" và bạn không giải thích BẤT CỨ lý do nào tại sao anh ta nên chọn một triển khai khác.
JNK

1
Chỉnh sửa tuyệt vời. Rất nhiều thông tin. Một điều nhỏ tôi muốn nói thêm là sự kế thừa bảng chứa đầy các vấn đề khó hiểu trong PostgreQuery. Nó có thể giải quyết các vấn đề quan trọng (và cũng có thể là một phần của giải pháp ở đây) nhưng nó không phải lúc nào cũng hoạt động theo cách mọi người mong đợi. Sử dụng một cách thận trọng. (Blog của tôi, ledgersmbdev.blogspot.com , có số lượng bài đăng khá lớn về loại điều này)
Chris Travers

6

Nếu cơ sở dữ liệu này theo bất kỳ cách nào được kết nối với những gì người tiêu dùng của bạn đang mua, hiệu suất sẽ sớm là một trong những vấn đề quan trọng nhất của bạn. Tôi không nói rằng EAV không có chỗ trong thế giới cơ sở dữ liệu, nhưng bạn có thể mang đến nhiều vấn đề hơn câu trả lời với mô hình này. Vì tôi phải tự mình quản lý một cơ sở dữ liệu (bên thứ 3) như vậy, đây là một số điều cần lưu ý:

  • Hiệu suất có thể trở nên tồi tệ khá nhanh: Nếu bạn muốn truy xuất tất cả các trường cho một sản phẩm nhất định, khách hàng ... bạn sẽ phải nhân các TRÁI PHIẾU, vì mỗi thuộc tính sẽ được lưu trữ trong một hàng khác nhau. Bây giờ hãy tưởng tượng khi bạn có hàng trăm lĩnh vực để tham gia.

  • tính toàn vẹn dữ liệu: sẽ rất khó để thực thi. Ví dụ, không ai ngăn khách hàng có hai (hoặc nhiều hơn) ngày sinh. Nếu isbn là cần thiết cho sách, làm thế nào bạn sẽ chắc chắn nó là? Loại trường sinh nhật của bạn sẽ là gì? Bạn có thể có rất nhiều mã để giúp bạn với điều này, nhưng nó sẽ khó và lâu để viết và chắc chắn sẽ ảnh hưởng đến hiệu suất.

Danh sách này có thể được tiếp tục và bài đọc yêu thích của tôi về chủ đề này là Bản sao thực dụng SQL của Bill Karwin. Bạn cũng có thể xem video này, Thực tiễn tốt nhất về SQL trong vòng chưa đầy 20 phút . Nhà cung cấp của chúng tôi không thể thay đổi kiến ​​trúc của họ ngay bây giờ (sẽ cần nhiều tháng thiết kế lại) và các vấn đề đang chồng chất cho khối lượng dữ liệu của chúng tôi. Cân nhắc những ưu và khuyết điểm trước khi đi xuống con đường này.


EAV hoạt động rất tốt đối với một số loại dữ liệu rất cụ thể, trong đó dữ liệu thực sự khớp với mô hình EAV. Ví dụ: các tham số cho một yêu cầu HTTP ..... Vì vậy, trong khi tôi chưa sẵn sàng để gọi nó là một phản mẫu theo cách phân loại, tôi hoàn toàn đồng ý rằng nó sẽ ở đây.
Chris Travers
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.