动态数据库架构


69

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

需要说明的是:在要求系统为模型提供存储的情况下,其模型可能会在生产后由其用户扩展或更改,那么有哪些好的技术,数据库模型或存储引擎可以做到这一点?

一些可能性来说明:

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

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

Answers:


38

您的建议并不新鲜。很多人都尝试过……大多数人发现他们追求“无限”的灵活性,而最终获得的收益却远不止于此。它是数据库设计的“蟑螂汽车旅馆”-可以输入数据,但是几乎不可能将其导出。尝试并针对任何类型的约束对代码进行概念化编写,您将明白我的意思。

最终结果通常是一个更难以调试,维护和充满数据一致性问题的系统。情况并非总是如此,但通常情况是这样的。主要是因为程序员看不到火车残骸的到来,并且无法针对它进行防御性编码。而且,通常最终会出现这样的情况,即“无限”的灵活性实际上并不是必需的。当开发团队得到一个说明说“天哪,我不知道他们将要放在这里的数据是什么,所以让它们放进去”时,这是一个非常糟糕的“气味”……而最终用户也很好具有可以使用的预定义属性类型(为通用电话号码编码,

如果您有一个非常优秀的开发团队,并且充分意识到使用此设计必须克服的问题,那么您可以成功编写出设计良好,而不是令人毛骨悚然的系统的代码。大多数时候。

但是,为什么为什么要从与您对立的赔率开始呢?

不相信我吗 Google“一个真实的查询表”或“单个表设计”。一些不错的结果: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


20

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


3
这是一项强大的技术,您在使用它之前应始终犹豫。绝对喜欢db规范化。也就是说,它确实有效,您可以查询数据(尽管很丑陋),并且性能还不错。
aboy021

17

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

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

如果您可以成功完成这些操作(尤其是第一个操作),那么您提到的任何体系结构都将起作用。我的首选是动态更改数据库对象,因为当您访问存储在自定义字段中的数据时,这使您可以利用DBMS的查询功能。其他三个选项要求您加载大量数据,然后在代码中进行大多数数据处理。


9

我有类似的要求,因此决定使用无模式的MongoDB

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

强调:

  • 具有丰富的查询功能(也许是最接近SQL数据库的数据库)
  • 生产就绪(foursquare,sourceforge使用它)

Lowdarks(您需要了解的东西,因此您可以正确使用mongo):


还有RavenDB,它符合ACID。
2014年

7

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

该数据库由一个表和一个字段组成,其中一个字段由50个数组组成。该字段上设置了“单词”索引。所有数据都是无类型的,因此“单词索引”按预期工作。数字字段表示为字符,并且实际排序已在客户端完成。(如果需要,每种数据类型仍然可以具有多个数组字段)。

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

优点:

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

缺点:

  1. 仅按完整词编制索引,无缩写,
  2. 可能进行复杂的查询,但性能会稍有下降。
  3. 取决于您的首选数据库系统是否支持数组和单词索引(在PROGRESS RDBMS中进行了补充)。
  4. 关系模型仅在程序员心中(即仅在运行时)。

现在我在想下一步可​​能是-在文件系统级别上实现这样的数据库。那可能比较容易。


7

建立关系数据库的全部目的是保持数据安全和一致。从允许用户更改架构的那一刻起,您的数据完整性就出现了……

如果您需要存储异构数据(例如CMS场景),则建议连续存储经过XSD验证的XML。当然,您会失去性能和简单的搜索功能,但这是对IMHO的一个很好的折衷。

既然是2016年,那就不用XML了!使用JSON来存储非关系数据包,并使用适当类型的列作为后端。通常,您不需要在bag内按值查询,这会很慢,即使许多现代SQL数据库本身就了解JSON。


3

在我看来,您真正想要的是某种“元模式”,这是一种数据库模式,能够描述用于存储实际数据的灵活模式。动态模式更改是敏感的,不是您想惹的麻烦,尤其是在允许用户进行更改的情况下。

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

为了澄清我的意思是“元模式”:

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

    PRIMARY KEY (id)
);

这是一个非常简单的示例,您可能会根据自己的需求找到一些更具体的东西(希望可以更轻松地使用它),但这确实可以说明我的观点。您应该认为数据库模式本身在应用程序级别是不可变的。任何结构上的更改都应反映在数据中(即该架构的实例化)。


3

我知道问题中指出的模型已在整个生产系统中使用。我供职的大型大学/教学机构正在使用一个相当大的应用程序。他们专门使用长的窄表方法来映射由许多不同的数据采集系统收集的数据。

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

检查以下内容:

实体-属性-价值模型

Google协议缓冲区


3

创建2个数据库

  • DB1包含静态表,并表示数据的“真实”状态。
  • DB2是免费的,用户可以根据自己的意愿进行操作-他们(或您)将不得不编写代码以从DB1中填充其奇数形的表。

2

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


这是在Magento中完成的。查询既繁琐又缓慢,但是非常灵活。
艾伦(Alan)

2

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

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

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

例:

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

物理数据库布局:

表“规格” :(应缓存在数据访问层中)

  • id:int
  • parent_id:整数
  • 名称:varchar(255)

表“项目”:

  • id:int
  • parent_id:整数
  • spec_id:整数
  • 数据: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 = "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
            )
    )

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

不好的例子,不要使用它,避免使用它,而是缓存规格表!

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"
            )
    )

我希望您能有所想法,并可以自己确定该方法是否对您可行。

请享用!:-)


1

在c2.com Wiki上,探讨了“动态关系”的概念。您不需要DBA:列和表都是写时创建的,除非您开始添加约束以使其表现得更像传统的RDBMS:随着项目的成熟,您可以逐步“锁定”它。

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

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

但这并不意味着它必须被实现为XML,它只是一个方便的概念化。如果您请求一个不存在的列,例如“ SELECT madeUpColumn ...”,则将其视为空白或空值(除非添加了约束禁止这样做)。并且可以使用SQL,尽管由于隐式类型模型,在比较时必须小心。但是除了类型处理之外,动态关系系统的用户会感到宾至如归,因为他们可以利用他们现有的大多数RDBMS知识。现在,如果有人愿意建造它...


0

过去,我选择了选项C-创建一个“长而狭窄”的表,将动态列值存储为行,然后需要对其进行透视处理以创建一个“短而宽”的行集,其中包含特定实体的所有值。。但是,我使用的是ORM,这确实使事情很痛苦。我想不出如何处理LinqToSql。我想我必须创建一个哈希表来引用字段。

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


0

ElasticSearch。特别是在处理可以按日期划分的数据集,可以对数据使用JSON且不固定使用SQL检索数据时,应该特别考虑这一点。

ES为您发送的任何新JSON字段(自动添加提示)或通过一个HTTP命令(“映射”)定义/更改自动推断您的模式。尽管它不支持SQL,但它具有一些强大的查找功能,甚至可以聚合。


0

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


-5

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

只是有一个表列出了不允许用户更改的字段,并为ALTER编写了一个不错的界面。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.