动态数据库架构

时间:2008-09-15 20:04:53

标签: sql database-design architecture dynamic-data

为动态逻辑数据库架构提供存储的推荐架构是什么?

澄清:如果系统需要为模型提供存储,其模式可能会被其用户在生产中扩展或更改,那么有哪些优秀的技术,数据库模型或存储引擎可以实现这一点?

有几种可能的说明:

  • 通过动态生成的DML创建/更改数据库对象
  • 创建包含大量稀疏物理列的表,并仅使用“覆盖”逻辑架构所需的表
  • 创建一个“长而窄”的表,该表将动态列值存储为需要旋转的行,以创建包含特定实体的所有值的“短,宽”行集
  • 使用BigTable / SimpleDB PropertyBag类型系统

任何基于现实世界经验的答案都将受到高度赞赏

17 个答案:

答案 0 :(得分:36)

你提出的建议并不新鲜。很多人都尝试过......大多数人都发现他们追求的是“无限”的灵活性,而不是最终的结果。这是数据库设计的“蟑螂汽车旅馆” - 数据进入,但几乎不可能把它拿出来。尝试并概念化为任何类型的约束编写代码,你会明白我的意思。

最终结果通常是一个更难以调试,维护和充满数据一致性问题的系统。这不是始终的情况,但通常情况下,它最终会如何。主要是因为程序员没有看到这个火车残骸即将到来并且未能防御性地编码。此外,通常最终会出现“无限”灵活性并非必要的情况;这是一个非常糟糕的“气味”,当开发团队得到一个规范,说“天哪我不知道他们将在这里放置什么样的数据,所以让他们把它放在什么地方......”最终用户就好了拥有他们可以使用的预定义属性类型(编写通用手机#,并让他们创建任何#他们 - 这在一个很好的规范化系统中是微不足道的,并保持灵活性和完整性!)

如果您拥有一支非常优秀的开发团队并且非常了解您必须克服此设计所遇到的问题,那么您可以成功编写一个设计良好,而不是非常错误的系统。大多数时候。

为什么要开始考虑那些对你不利的赔率?

不相信我?谷歌“One True Lookup Table”或“单桌设计”。一些好的结果: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:10678084117056

http://thedailywtf.com/Comments/Tom_Kyte_on_The_Ultimate_Extensibility.aspx?pg=3

http://www.dbazine.com/ofinterest/oi-articles/celko22

http://thedailywtf.com/Comments/The_Inner-Platform_Effect.aspx?pg=2

答案 1 :(得分:19)

MSSQL中的强类型xml字段对我们有用。

答案 2 :(得分:15)

像其他人所说的那样,除非你别无选择,否则不要这样做。需要这种情况的一种情况是,如果您要销售必须允许用户记录自定义数据的现成产品。我公司的产品属于这一类。

如果您确实需要允许客户这样做,请参考以下几点提示:
  - 创建强大的管理工具来执行架构更改,并且不允许以任何其他方式进行这些更改。
  - 使其成为一种管理功能;不允许普通用户访问它   - 记录每个架构更改的每个细节。这将帮助您调试问题,如果客户做了一些愚蠢的事情,它也会为您提供CYA数据。

如果你能成功地完成这些事情(特别是第一个),那么你提到的任何架构都可以工作。我的首选是动态更改数据库对象,因为这样可以在访问存储在自定义字段中的数据时利用DBMS的查询功能。其他三个选项要求您加载大量数据,然后在代码中执行大部分数据处理。

答案 3 :(得分:9)

我有类似的要求,并决定使用无架构MongoDB

  

MongoDB(来自“humongous”)是一个用C ++编程语言编写的开源,可扩展,高性能,无架构,面向文档的数据库。 (维基百科)

亮点:

  • 具有丰富的查询功能(可能最接近SQL DB)
  • 生产就绪(foursquare,sourceforge使用它)

Lowdarks(你需要了解的东西,所以你可以正确使用mongo):

答案 4 :(得分:7)

我在一个真实的项目中做到了:

数据库由一个表组成,其中一个字段是一个50的数组。它上面有一个'word'索引。所有数据都是无类型的,因此'word index'按预期工作。数字字段表示为字符,实际排序已在客户端完成。 (如果需要,仍然可以为每种数据类型提供多个数组字段。)

逻辑表的逻辑数据模式保存在具有不同表行“类型”(第一个数组元素)的同一数据库中。它还支持使用相同的“类型”字段进行写时复制样式的简单版本控制。

优点:

  1. 您可以动态重新排列和添加/删除列,无需转储/重新加载数据库。任何新的列数据都可以在零时间内(虚拟地)设置为初始值。
  2. 碎片是最小的,因为所有记录和表都是相同的大小,有时它会提供更好的性能。
  3. 所有表架构都是虚拟的。任何逻辑模式结构都是可能的(甚至是递归的,或面向对象的)。
  4. 这对“一次写入,多次读取,不删除/删除标记”数据很有用(大多数Web应用实际上就是这样)。
  5. 缺点:

    1. 仅使用完整字词,无缩写
    2. 进行索引
    3. 可以进行复杂查询,但性能略有下降。
    4. 取决于您的首选数据库系统是否支持数组和单词索引(它是在PROGRESS RDBMS中添加的。)
    5. 关系模型仅在程序员的脑海中(即仅在运行时)。
    6. 现在我认为下一步可能是 - 在文件系统级别实现这样的数据库。这可能相对容易。

答案 5 :(得分:6)

拥有关系数据库的重点是保证数据的安全性和一致性。当您允许用户更改架构时,您的数据完整性就会......

如果您需要存储异构数据,例如CMS场景,我建议将XSD验证的XML存储在一行中。当然,你会失去性能和简单的搜索功能,但这是一个很好的权衡恕我直言。

从2016年开始,忘记XML了!使用JSON存储非关系数据包,并使用适当类型的列作为后端。您通常不需要通过包中的值进行查询,即使许多当代SQL数据库本身都了解JSON,这也会很慢。

答案 6 :(得分:3)

创建2个数据库

  • DB1包含静态表,表示数据的“实际”状态。
  • DB2可供用户随意使用 - 他们(或您)必须编写代码来填充DB1中奇形状的表。

答案 7 :(得分:3)

我知道问题中指出的模型全部用于生产系统。在我工作的大型大学/教学机构中使用了相当大的一个。他们专门使用长窄表方法来映射由许多不同数据采集系统收集的数据。

此外,谷歌最近通过其代码网站发布了他们的内部数据共享协议协议缓冲区作为开源。以这种方法建模的数据库系统将非常有趣。

检查以下内容:

Entity-attribute-value model

Google Protocol Buffer

答案 8 :(得分:3)

听起来像你真正想要的是某种“元模式”,这是一种能够描述用于存储实际数据的灵活模式的数据库模式。动态架构更改非常棘手,而不是您想要处理的内容,尤其是在允许用户进行更改的情况下。

您不会找到比任何其他更适合此任务的数据库,因此您最好的选择是根据其他条件选择一个。例如,您使用什么平台来托管数据库?该应用程序使用什么语言编写?等

澄清“meta-schema”的含义:

CREATE TABLE data (
    id INTEGER NOT NULL AUTO_INCREMENT,
    key VARCHAR(255),
    data TEXT,

    PRIMARY KEY (id)
);

这是一个非常简单的例子,你可能会有更具体的需求(希望更容易使用),但它确实可以说明我的观点。您应该认为数据库模式本身在应用程序级别是不可变的;任何结构变化都应反映在数据中(即该模式的实例化)。

答案 9 :(得分:2)

我相信EAV方法是最好的方法,但需要花费很高的成本

答案 10 :(得分:2)

维基百科对问题空间有一个很好的概述:

http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model

答案 11 :(得分:2)

我知道这是一个古老的话题,但我想它永远不会失去现实。 我正在开发类似的东西。 这是我的方法。 我使用带有MySQL,Apache,PHP和Zend Framework 2的服务器设置作为应用程序框架,但它应该可以与任何其他设置一起使用。

这是一个简单的实施指南,您可以自己进一步发展它。

您需要实现自己的查询语言解释器,因为有效的SQL太复杂了。

示例:

select id, password from user where email_address = "xyz@xyz.com"

物理数据库布局:

表'规格':(应该缓存在您的数据访问层中)

  • id:int
  • parent_id:int
  • name:varchar(255)

表'项':

  • id:int
  • parent_id:int
  • spec_id:int
  • data:varchar(20000)

表'规格'的内容:

  • 1,0,'用户'
  • 2,1,'email_address'
  • 3,1,'password'

表'items'的内容:

  • 1,0,1,''
  • 2,1,2,'xyz @ xyz.com'
  • 3,1,3,'我的密码'

使用我们自己的查询语言翻译示例:

select id, password from user where email_address = "xyz@xyz.com"

标准SQL看起来像这样:

select 
    parent_id, -- user id
    data -- password
from 
    items 
where 
    spec_id = 3 -- make sure this is a 'password' item
    and 
    parent_id in 
    ( -- get the 'user' item to which this 'password' item belongs
        select 
            id 
        from 
            items 
        where 
            spec_id = 1 -- make sure this is a 'user' item
            and 
            id in 
            ( -- fetch all item id's with the desired 'email_address' child item
                select 
                    parent_id -- id of the parent item of the 'email_address' item
                from 
                    items 
                where 
                    spec_id = 2 -- make sure this is a 'email_address' item
                    and
                    data = "xyz@xyz.com" -- with the desired data value
            )
    )

您需要将specs表缓存在关联数组或哈希表或类似的东西中,以从规范名称中获取spec_id。否则,您需要插入更多的SQL开销来从名称中获取spec_id,例如在此片段中:

错误的例子,不要使用它,避免这种情况,而是缓存specs表!

select 
    parent_id, 
    data 
from 
    items 
where 
    spec_id = (select id from specs where name = "password") 
    and 
    parent_id in (
        select 
            id 
        from 
            items 
        where 
            spec_id = (select id from specs where name = "user") 
            and 
            id in (
                select 
                    parent_id 
                from 
                    items 
                where 
                    spec_id = (select id from specs where name = "email_address") 
                    and 
                    data = "xyz@xyz.com"
            )
    )

我希望你明白这个想法,并且可以自己确定这种方法对你来说是否可行。

享受! : - )

答案 12 :(得分:0)

过去我选择了选项C - 创建一个'long,narrow'表,它将动态列值存储为需要旋转的行,以创建一个包含所有的“短,宽”行集特定实体的价值。。但是,我使用的是ORM,这真让人感到痛苦。我想不出你是怎么做的,比如LinqToSql。我想我必须创建一个Hashtable来引用这些字段。

@Skliwz:我猜他更感兴趣的是允许用户创建用户定义的字段。

答案 13 :(得分:0)

ElasticSearch。您应该考虑它,特别是如果您正在处理可以按日期分区的数据集,您可以将JSON用于您的数据,并且不会使用SQL来检索数据。

ES为您发送的任何新JSON字段推断您的架构,可以自动,使用提示,也可以手动为一个HTTP命令(“映射”)定义/更改。 虽然它不支持SQL,但它具有一些出色的查找功能甚至聚合功能。

答案 14 :(得分:0)

在c2.com维基上,探讨了“动态关系”的概念。您不需要DBA:列和表是Create-On-Write,除非您开始添加约束以使其更像传统的RDBMS:随着项目的成熟,您可以逐步“锁定”。

从概念上讲,您可以将每一行视为XML语句。例如,员工记录可以表示为:

<employee lastname="Li" firstname="Joe" salary="120000" id="318"/>

暗示它必须以XML格式实现,这只是一个方便的概念化。如果您要求一个不存在的列,例如“SELECT madeUpColumn ...”,则将其视为空白或null(除非添加了约束禁止此类)。并且可以使用 SQL ,但由于隐含的类型模型,必须要小心比较。但除了类型处理之外,动态关系系统的用户会感到宾至如归,因为他们可以充分利用现有的RDBMS知识。现在,如果有人想建立它......

答案 15 :(得分:0)

我知道这是一篇过时的文章,并且在过去11年中发生了很多变化,但是我想添加一下,因为这可能对将来的读者有所帮助。我和我的共同创始人创建HarperDB的原因之一是在提供完整索引功能的同时,在单个无重复的数据集中本地完成Dynamic模式。您可以在此处了解更多信息:
https://harperdb.io/blog/dynamic-schema-the-harperdb-way/

答案 16 :(得分:-5)

sql已经提供了一种更改架构的方法:ALTER命令。

只需要一个表,列出不允许用户更改的字段,并为ALTER编写一个很好的界面。