SQL 中实体-属性-值数据库设计的主要缺点似乎都与能够高效快速地查询和报告数据有关。由于这些问题以及几乎所有应用程序的查询/报告的共性,我阅读的有关该主题的大多数信息都警告不要实施 EAV。
我目前正在设计一个系统,其中一个实体的字段在设计/编译时是未知的,并且由系统的最终用户定义。EAV 似乎很适合这个要求,但由于我读到的问题,我在实施它时犹豫不决,因为这个系统也有一些非常繁重的报告要求。我想我已经想出了解决这个问题的方法,但想向 SO 社区提出这个问题。
鉴于典型的规范化数据库 (OLTP) 并不总是运行报告的最佳选择,一个好的做法似乎是拥有一个“报告”数据库 (OLAP),将规范化数据库中的数据复制到该数据库中,并对其进行广泛索引,并且可能非规范化以便于查询。是否可以使用相同的想法来解决 EAV 设计的缺点?
我看到的主要缺点是将数据从 EAV 数据库传输到报告的复杂性增加,因为您可能最终不得不更改报告数据库中的表,因为在 EAV 数据库中定义了新字段。但这几乎是不可能的,而且对于 EAV 设计所赋予的更大灵活性而言,这似乎是一个可以接受的折衷方案。如果我使用非 SQL 数据存储(即 CouchDB 或类似数据)作为主要数据存储,也会存在此缺点,因为所有标准报告工具都期望 SQL 后端进行查询。
如果您有一个单独的报告数据库进行查询,EAV 系统的问题是否大部分都消失了?
编辑:感谢到目前为止的评论。关于我正在研究的系统的重要事情之一是我实际上只是在谈论将 EAV 用于其中一个实体,而不是系统中的所有内容。
该系统的整个要点是能够从多个不同的来源提取数据,这些来源事先不知道,并对数据进行处理以得出一些关于特定实体的“最知名”数据。因此,我处理的每个“字段”都是多值的,我还需要跟踪每个“字段”的历史记录。对此的规范化设计最终是每个字段 1 个表,这使得查询它无论如何都是痛苦的。
这是我正在查看的表模式和示例数据(显然与我正在研究的内容有所不同,但我认为它很好地说明了这一点):
EAV 表
Person
-------------------
- Id - Name -
-------------------
- 123 - Joe Smith -
-------------------
Person_Value
-------------------------------------------------------------------
- PersonId - Source - Field - Value - EffectiveDate -
-------------------------------------------------------------------
- 123 - CIA - HomeAddress - 123 Cherry Ln - 2010-03-26 -
- 123 - DMV - HomeAddress - 561 Stoney Rd - 2010-02-15 -
- 123 - FBI - HomeAddress - 676 Lancas Dr - 2010-03-01 -
-------------------------------------------------------------------
报告表
Person_Denormalized
----------------------------------------------------------------------------------------
- Id - Name - HomeAddress - HomeAddress_Confidence - HomeAddress_EffectiveDate -
----------------------------------------------------------------------------------------
- 123 - Joe Smith - 123 Cherry Ln - 0.713 - 2010-03-26 -
----------------------------------------------------------------------------------------
标准化设计
Person
-------------------
- Id - Name -
-------------------
- 123 - Joe Smith -
-------------------
Person_HomeAddress
------------------------------------------------------
- PersonId - Source - Value - Effective Date -
------------------------------------------------------
- 123 - CIA - 123 Cherry Ln - 2010-03-26 -
- 123 - DMV - 561 Stoney Rd - 2010-02-15 -
- 123 - FBI - 676 Lancas Dr - 2010-03-01 -
------------------------------------------------------
此处的“信心”字段是使用 SQL 无法轻松表达(如果有的话)的逻辑生成的,因此除了插入新值之外,我最常见的操作是为所有字段提取有关一个人的所有数据,以便我可以生成记录报告表。这在 EAV 模型中实际上更容易,因为我可以执行单个查询。在规范化设计中,我最终不得不对每个字段进行 1 次查询,以避免大量笛卡尔积将它们连接在一起。