您将如何设计数据库以允许用户定义模式

Posted

技术标签:

【中文标题】您将如何设计数据库以允许用户定义模式【英文标题】:How would you design your database to allow user-defined schema 【发布时间】:2010-10-29 18:07:56 【问题描述】:

如果您必须创建一个应用程序,比如博客应用程序,那么创建数据库模式相对简单。你必须创建一些表格、tblPosts、tblAttachments、tblCommets、tblBlaBla……就是这样(好吧,我知道,这有点简化,但你明白我的意思)。

如果您有一个应用程序,您希望允许用户在运行时定义部分架构。假设您要构建一个应用程序,用户可以在其中记录任何类型的数据。一位用户想要记录他的工作时间(开始时间、结束时间、项目 ID、描述),下一位想要收集烹饪食谱、其他人可能是股票报价、他们的孩子每周的体重、他们每月花费的食物费用、他们的结果最喜欢的足球队或任何你能想到的东西。

您将如何设计一个数据库来保存所有这些非常不同类型的数据?你会创建一个可以保存所有类型数据的通用模式,你会创建反映用户数据模式的新表,还是你有另一个好主意?

如果它很重要:我必须使用 SQL Server / Entity Framework

【问题讨论】:

【参考方案1】:

您无法预测他们的数据需求会有多复杂。实体-属性-值是许多程序员使用的一种典型解决方案,但它可能就足够了,例如,如果用户的数据通常使用多个表进行建模。

我会将用户的自定义数据序列化为 XML 或 YAML 或 JSON 或类似的半结构化格式,并将其保存在文本 BLOB 中。

您甚至可以创建倒排索引,以便在 BLOB 的属性中查找特定值。请参阅http://bret.appspot.com/entry/how-friendfeed-uses-mysql(该技术适用于任何 RDBMS,而不仅仅是 MySQL)。

还可以考虑使用Solr 或MongoDB 等文档存储。这些技术不需要遵守关系数据库约定。您可以在运行时向任何文档添加新属性,而无需重新定义架构。但这是一种权衡——没有架构意味着您的应用不能依赖于整个集合中相似的文档/行。


我是实体-属性-值反模式的批评者。

我在我的书中写过 EAV 问题,SQL Antipatterns: Avoiding the Pitfalls of Database Programming。

这是一个 SO 答案,我列出了 Entity-Attribute-Value 的一些问题:“Product table, many kinds of products, each product has many parameters。”

这是我前几天发布的一篇关于 EAV 问题的更多讨论的博客:“EAV FAIL。”

请务必阅读此博客“Bad CaRMa”,了解如何尝试创建一个完全灵活的数据库几乎摧毁了一家公司。

【讨论】:

想详细说明您对 EAV Bill 的批评吗?我认为它有它的位置,虽然当然有限制,但请参阅我的回复中的链接。 所有东西的blob?呸!这将使即使是简单的报告也几乎是不可能的,而且获得良好的性能也将变得更加困难。 @Booji Boy:我同意,在 SQL 中分离 XML(或其他)很难,但 OP 并没有说他需要做任何报告。很有可能整个 blob 都必须加载到应用程序中才能执行用户想要对其执行的任何操作。无论如何,这很难预料。 @Bill,我同意没有完美的解决方案。审计也有一些有趣的交叉。我想说的一点是,“值”部分(列或单独的表)不仅必须由单个列组成,每种数据类型都可以作为单独的列存在,这是“属性'来确定要使用的列(数据类型)。 @Si:对,我也看到了那个解决方案。它解决了数据类型验证的问题,但没有解决 EAV 的其他问题。此外,它使查询更加难以理解。【参考方案2】:

让我们再试一次。

如果您希望他们能够创建自己的架构,那么为什么不使用 CREATE TABLE 语句来构建架构,哦,我不知道。你有一个完整的、功能齐全的、强大的数据库,可以做一些很棒的事情,比如定义模式和存储数据。为什么不使用它?

如果您只是要做一些临时属性,那么当然可以。

但如果是“全权委托,他们可以为所欲为”,那就让他们去做吧。

他们必须了解 SQL 吗?嗯,没有。那是您的 UI 任务。作为工具和应用程序设计者,您的工作是向用户隐藏实现。因此,如果您需要关系等,请提供字段、线条和箭头的列表。随便。

多年来,人们一直在制作“最终用户”、“简单”的数据库工具。

“如果他们想添加一列怎么办?”然后添加一列,数据库会这样做,至少大多数好的。如果没有,则创建新表,复制旧数据,删除旧表。

“如果他们想删除一列怎么办?”往上看。如果您的无法删除列,则将其从用户的逻辑视图中删除,使其看起来已被删除。

“如果他们有 110 亿行数据怎么办?”然后他们有 110 亿行数据,并且操作花费的时间比他们有 1 行数据要长 110 亿倍。如果他们有 110 亿行数据,他们可能无论如何都不应该使用您的系统。

“在数据库上实现数据库”的魅力让我无法理解。

“我这里有Oracle,我怎么能提供更少的功能,让用户更慢??”

哎呀,我想知道。

【讨论】:

你忘了提到索引。除非它提供了一种索引所有新属性的方法,否则没有准备好数据库包装器,然后...... 这个话题终于有了一个明智的答案。 ““在数据库上实现数据库”的魅力让我无法理解。”极好的!! :) 喜欢这个答案。完美诠释Inner Platform Effect【参考方案3】:

与其重新实现 sqlservers "CREATE TABLE" 语句,这是由一个可能比您或我更好的程序员团队在多年前完成的,为什么不以有限的方式向用户公开 SQLSERVER ——让他们以有限的方式创建自己的架构,并利用 SQLServer 的力量来正确地完成它。

【讨论】:

这实际上是一个很棒的评论。但由于这是一个实体框架问题,因此需要更新您的实体以合并这些字段。那么你不妨添加它们。其次,值得注意的是,用户更改您的 SQL 架构可能会对性能产生严重影响(需要重新计算执行计划等)【参考方案4】:

我会选择混合实体-属性-值模型,因此就像 Antony 的回复一样,您有 EAV 表,但您也有始终存在的默认列(和类属性)。

这是一个great article,关于你的目的:)

作为补充评论,我在几天内使用 Linq2Sql 为这种方法敲了一个原型,这是一个可行的解决方案。鉴于您提到了实体框架,我会看看第 4 版及其POCO support,因为这将是注入混合 EAV 模型而不会污染您的 EF 架构的好方法。

【讨论】:

这是一篇很棒的文章,你找到了 Si - 为下次添加书签!【参考方案5】:

不是批评性评论,但它可能会帮助您节省一些时间来指出这是堂吉诃德圣杯类型的问题之一。大约 50 多年来,人们一直在不断追求打造用户友好的数据库设计界面。

我能想到的唯一获得显着吸引力的准成功者是 1. Excel(及其前身),2. Filemaker(原始版本,而不是当前版本)和 3.(可能,但怀疑)访问。请注意,前两个基本上仅限于一个表。

如果我们的集体传统智慧能够帮助您打破障碍,我会感到惊讶。但这会很棒。

【讨论】:

第二个,你可以非常有限并且完全无法使用某些实体属性方案,或者,你可以想出一些灵活、复杂和噩梦来维护的东西,这实际上只是一个糟糕的实现数据定义语言。【参考方案6】:

看看这个post,你可以做到,但这是一项艰巨的工作:) 如果性能不是问题,xml 解决方案也可以工作,尽管这也是很多工作。

【讨论】:

我知道那篇文章,但我不知道为什么这应该是我问题的答案!? 很公平,是一个快速的答案。您当然可以将架构的“动态”部分留给其他引擎,这无论如何都是领域驱动设计的美感,但我很难弄清楚如何使用 EF 或 L2S 解决这个问题。我的意思是,无论如何,哪种类型的应用程序会针对记录每个人的各种需求?只是为了好玩还是真正的项目?【参考方案7】:

我不熟悉实体框架,但我倾向于实体-属性-值 (http://en.wikipedia.org/wiki/Entity-Attribute-Value_model) 数据库模型。

因此,您的应用将创建属性(或属性集合),然后您的最终用户将完成这些值,而不是动态创建表和列。

但是,正如我所说,我不知道实体框架应该为您做什么,它可能不会让您采用这种方法。

【讨论】:

FWIW,Entity Framework 是 Microsoft .NET 框架的新生 ORM 库。 感谢 Bill - 我不是 .NET 人,所以从未听说过。不过,我在想,ORM 会与 EAV 发生冲突吗? 使用 ORM 是可能的(实际上更简单!),您可以拥有一个由一些 EAV 接口属性组成的业务对象接口。例如IEntity 由 List 组成,其中 IAttribute 由 List 组成(并且还链接回 IEntity)。只要您以 ORM 工具的标准方式定义实体 -> 属性 -> 值,它就像任何其他关系一样。【参考方案8】:

从表面上看,用于自定义用户数据的无模式或面向文档的数据库(例如 CouchDB 或 SimpleDB)听起来很理想。但我想如果你只能使用 SQL 和 EF 之外的任何东西,这并没有多大帮助。

【讨论】:

【参考方案9】:

我会给他们一份 SQL Server Management Studio 的副本,然后说:“发疯!”为什么要在轮中重新发明***?

【讨论】:

这不是一个好主意,因为用户不知道“SQL”或“Management Studio”是什么。有趣的答案,但没有真正的帮助。

以上是关于您将如何设计数据库以允许用户定义模式的主要内容,如果未能解决你的问题,请参考以下文章

具有 PHP + MySQL 后端的 JS(Angular) 前端用户权限

您将如何在 C# 中实现“特征”设计模式?

如何使用 WCF 数据服务公开非持久属性?

设计模式--策略模式

无论计算模式如何,您将如何编写手动计算的 excel udf?

django 设计模式/最佳实践:过滤查询集