it-swarm.cn

动态数据库架构

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

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

一些可能的说明:

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

任何基于现实世界经验的答案都将不胜感激

63
Fake Jim

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

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

如果你有一个非常好的开发团队并且 非常清楚 你需要克服这个设计的问题,你可以成功编写一个设计良好,而不是非常错误的系统。大多数时候。

不过,为什么要开始考虑那么多的赔率呢?

不相信我?谷歌“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

36
Matt Rogish

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

19
Bloodhound

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

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

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

15
Josh Yeager

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

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

强调:

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

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

9
clyfe

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

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

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

好处:

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

缺点:

  1. 仅使用完整单词索引,无缩写,
  2. 复杂查询是可能的,但性能略有下降。
  3. 取决于您的首选数据库系统是否支持数组和Word索引(它是在PROGRESS RDBMS中添加的)。
  4. 关系模型仅在程序员的脑海中(即仅在运行时)。

而现在我认为下一步可能是 - 在文件系统级别实现这样的数据库。这可能相对容易。

7
Thevs

拥有关系数据库的关键在于保持数据的安全性和一致性。在您允许用户更改架构的那一刻,您的数据完整性就会出现......

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

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

6
Sklivvz

创建2个数据库

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

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

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

澄清我所说的“元模式”:

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

    PRIMARY KEY (id)
);

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

3
Daniel Spiewak

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

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

检查以下内容:

实体 - 属性 - 值模型

Google协议缓冲区

3
siculars

我认为EAV方法是最好的方法,但需要付出沉重的代价

2
kamal

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

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

2
DenNukem

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

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

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

例:

select id, password from user where email_address = "[email protected]"

物理数据库布局:

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

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

表'项':

  • id:int
  • parent_id:int
  • spec_id:int
  • 数据:varchar(20000)

表'规格'的内容:

  • 1,0,'用户'
  • 2,1,'email_address'
  • 3,1,'密码'

表'items'的内容:

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

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

select id, password from user where email_address = "[email protected]"

标准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 = "[email protected]" -- 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 = "[email protected]"
            )
    )

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

请享用! :-)

2
Oliver Konig

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

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

0
Danimal

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

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

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

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

0
FloverOwe

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

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

0
Oren