如何为未知类型的数据创建数据库?

mal*_*yeb 7 mysql database-design

我正在为新的基于 PHP/MySql 的应用程序设计数据库。

我的问题是我没有也不能代表应该保存在数据库中的内容,因为它是无限的并且不断变化。

这是问题示例:该应用程序将是一个购物网站,其中包含多种产品,所有产品都具有一些共享属性,例如title和,price但有些类型具有特定的详细信息,例如expiry date有些具有isbn一些非。

这只是一个例子,但我真的有很多不同属性的种类。

我可以为每个种类创建一个表格,但我拥有的并不是所有可用的种类,目前还有很多种类的项目是未知的。

他们是一种解决这个问题的方法吗?

Chr*_*ers 10

未知种类的数据对我来说听起来有些可疑。当然,你的例子都是众所周知的。对于商品和服务,仔细分析和规范化很重要,我认为您可以摆脱核心数据的 EAV 建模(我认为这会导致比解决的问题更多)。其余的可以填充在 XML 字段等中。此外,如果您的设计正确,您始终可以适当地扩展信息。考虑以下三个表:

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)
);
Run Code Online (Sandbox Code Playgroud)

现在有了这个,您可以将条码(包括 ISBN、EAN、UPC 等)分配给各个部分,每个品牌/型号组合一个。如果您需要支持更多条码类型,这不难添加。至于到期日期,这些去哪里取决于你在哪里跟踪它们。如果你想有临时定价,或者为一组客户定价,你也可以添加它。

但是,您所描述的内容听起来并不是很结构化。我建议从最小的设计开始,然后根据需要进行扩展,而不是 EAV 设计,然后再后悔。


Aar*_*and 9

这里有一些 SQL Server 的细节,但我总体上介绍了 EAV。它并不是人们常说的魔鬼,一些典型的借口问题是可以避免的。例如,@KookieMonster 说你不能强制用户没有两个生日,但这很容易:

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)
);
Run Code Online (Sandbox Code Playgroud)

(同样,这是 SQL Server 语法,但希望这个概念能引起共鸣。)

如果逻辑比这更复杂(例如,它们可以有三个电话号码但只有一个生日),那么它会变得更加复杂,但您仍然可以使用触发器、存储过程等强制执行与您的业务逻辑相匹配的事情。我不知道任何其他解决方案将如何更好地解决这个问题,同时不引入其他解决方案。

性能可能是一个问题,但是我们在 SQL Server 2008+ 中使用过滤索引(针对特定属性)和非规范化表的惰性物化解决了这个问题。对于缓慢变化的属性集,很容易进行后台处理,使表变平,以便对于某些或所有产品,您拥有数据的物化、透视版本以避免所有连接。这在 MySQL 中是如何工作的我不太确定,所以我不会提供语法,但也许我会从 SQL Server 的角度进一步讨论这个问题......


Pad*_*oll 7

不要使用MySQL,关系型数据库不用于解决此类问题。在 Windows 上使用文档或 NoSQL 数据库,例如 MongoDB 或可能的 RavenDB。

或者也可以使用 PostgreSQL。如果您有一组基本属性,则可以将继承构建到您的表中

create table base_items
( id bigint,
title varchar(50),
price money)
Run Code Online (Sandbox Code Playgroud)

然后对于其他物品,比如书或食物

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

create table food_items (date expiry_date)
inherits(base_items)
Run Code Online (Sandbox Code Playgroud)

让你的数据

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);
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 不要只是在这里抛出这样的一句话。这样的句子不是用来回答这类问题的,而是用来卖东西的。在 DBA.SE 上使用说明。 (5认同)
  • @PaddyCarroll 虽然我不同意答案的本质,但我并没有对此投反对票。我投了反对票,因为你的回答太短了。看,即使你对克里斯的评论回应也比你的回答长。请把这个(以及你有的任何其他理由)作为你的答案,我很乐意推翻我的投票。我认为没有人反对本网站上的不同观点,但我们确实反对较少解释和合理的答案。 (4认同)
  • @PaddyCarroll 请在此答案中添加更多内容,否则我会将其视为评论并为您转换。“不要那样做”不是答案,除非它还包括“改为这样做”并且您没有解释为什么他应该选择一种实现而不是另一种实现。 (4认同)
  • 您可能是对的,但我承认,缺少几点:为什么使用 NoSQL、针对 EAV 的优势、超类型-子类型、Chris 的建议或其他可能的解决方案(稀疏表等) (3认同)

Koo*_*ter 6

如果该数据库以任何方式与您的消费者所购买的产品相关联,那么性能很快就会成为您最重要的问题之一。我并不是说 EAV 在数据库世界中没有立足之地,但您可能会带来比此模型更多的问题的答案。由于我必须自己管理一个这样的(第 3 方)数据库,因此需要记住以下几点:

  • 性能会很快变差:如果您想检索给定产品、客户的所有字段……您必须乘以 LEFT JOIN,因为每个属性都将存储在不同的行中。现在想象一下,当您有数百个字段要加入时。

  • 数据完整性:很难执行。例如,没有人阻止客户有两个(或更多)出生日期。如果书籍需要 isbn,您将如何确保它是?你的生日字段的字段类型是什么?您可以有很多代码来帮助您解决这个问题,但是编写起来既困难又漫长,并且肯定会影响性能。

这个列表可以继续下去,我最喜欢的关于这个主题的读物是Bill Karwin 的Pragmatic SQL Antipatterns。您还可以观看此视频,不到 20 分钟的 SQL 最佳实践。我们的供应商现在无法改变他们的架构(需要几个月的重新设计),而且我们的数据量问题正在堆积如山。在走这条路之前,仔细权衡利弊。