EAV vs Serialized Object vs SQL with Xpath?

时间:2011-05-13 23:40:11

标签: sql database-design doctrine-orm

我正在尝试实施徽章系统,徽章基于用户的元数据,可能会有所变化。

这些元数据是可变的,并且是即时设置的。

元数据示例:

  • commentCount
  • hasCompletedProfile
  • isActiveMember

等。稍后,我想添加hasGravatar元数据,因此,我无法轻松设计和规范化表格。

这些数据虽然是应用程序的重要组成部分并不“合理”,但几乎所有这些元数据都可以重新计算,这意味着数据的完整性不是约束的一部分。

目前,我知道三个选项,即使我不知道其中任何一个。

  • EAV
  • 序列化对象
  • XML Field(我在某处读到可以在列中存储XML,并使用XPATH或其他东西来查询数据)

所有这些选项看起来都有专业版。但是由于我从未尝试过它们,我真的不知道哪个。

您有任何意见或建议吗?

我目前正在使用Zend Framework&带有MySQL服务器的Doctrine 2

2 个答案:

答案 0 :(得分:2)

XML和序列化对象都非常相似,因为您可能会使用1列来存储此任意数据。这很快变得非常混乱,很难在SQL WHERE子句中轻松区分(尽管有些DBMS支持XPath)

另一方面,EAV将为您拥有的每个Key => Value对提供一个单独的行,您可以使用JOIN或子查询轻松提取该行。如果你在这里有一个很多的数据,它可能会受到性能影响。另一个缺点是,为了简单起见,您将所有键/值存储为数据库中的文本。您可以为每种类型创建一个EAV表,但在大多数语言中并不需要它,因为您获取的内容可以作为字符串出现,或者无论如何都可以在那里进行转换。简单地存储用户配置/属性对于EAV应该是完全正常的。

所以你可能有一个包含3个字段的表user_metadata

metadata_id INTEGER
user_id INTEGER
key CHAR
value CHAR

然后,您可以为用户一次性获取此数据:

SELECT * FROM user_metadata WHERE metadata_user_id = $user_id

或者您可以获取单个元数据以及您的用户数据

SELECT user.*, meta_gravatar.value AS hasGravatar
FROM user
LEFT JOIN user_metadata AS meta_gravatar
 ON meta_gravatar.user_id = user.user_id AND meta_gravatar.key = 'hasGravatar'
WHERE user.user_id = $user_id

答案 1 :(得分:0)

EAV:这很复杂而且很慢。这是一个示例,说明如何不使用SQL数据库。您无法对EAV中的属性建立索引,并且需要一些非平凡的逻辑才能将数据从数据库获取到业务逻辑对象中。另外,您的SQL查询也变得难以优化。

序列化的对象:序列化通常取决于语言或平台。无法在某些属性上建立索引或搜索任何内容,但这是存储未定义结构的数据的简单方法。

XML字段:使用标准化表示要好于序列化。另外,您的SQL Server中可能支​​持这种数据结构。

JSON字段:与XML字段相同,但是JSON支持原始数据类型(int,bool,null),并且比XML解析和序列化更快,更容易。一些SQL Server也提供了一些支持。

所有三种序列化方法都有相同的缺点:属性上没有索引。在大多数应用程序中,这是可以接受的,因为数据库无论如何都不会处理数据,因此它们只是应用程序的一个Blob。好处是,此blob不会使数据库架构和操作复杂化。

还有另一种方法来实现这种EAV替代方法:普通的旧SQL表。如果新属性需要在应用程序代码中进行某些更改,则也可以添加SQL列。如果您具有在运行时定义属性的用户界面和应用程序逻辑,则可以教您的应用程序使用ALTER TABLE查询。然后,您只需根据需要添加或删除列。最后,只要您有一个好的查询构建器,它将比实现EAV更加容易和有效。