dynamic数据库模式
什么是为dynamic逻辑数据库模式提供存储的推荐体系结构?
澄清:如果需要系统为其模式在其生产中可能被其用户扩展或更改的模型提供存储,那么有哪些好的技术,数据库模型或存储引擎可以实现这一点?
有几种可能性来说明:
- 通过dynamic生成的DML创build/更改数据库对象
- 创build具有大量稀疏物理列的表格,并仅使用“覆盖”逻辑模式所需的表格
- 创build一个“长而窄”的表,该表将dynamic列值存储为行,然后需要对其进行旋转以创build包含特定实体的所有值的“short,wide”行集
- 使用BigTable / SimpleDB PropertyBagtypes系统
任何基于现实世界的经验的答案将不胜感激
你提出的是不是新的。 很多人已经尝试过……大多数人已经发现他们追求“无限”的灵活性,而最终得到的却远不止于此。 这是数据库devise的“蟑螂汽车旅馆” – 数据进入,但几乎不可能把它弄出来。 尝试和概念化编写任何types的约束的代码,你会明白我的意思。
最终结果通常是一个更难以debugging,维护和充满数据一致性问题的系统。 情况并非总是如此,但往往不是,这就是结局。 主要是因为程序员没有看到这个火车残骸来了,并且没有防守地对它进行编码。 而且,通常情况下,“无限”的灵活性实际上并不是那么必要; 当开发团队得到一个规范说:“我不知道他们要把什么样的数据放在这里,所以让我们把它放在这里,…”,而最终用户就好了,这是一个非常糟糕的“味道”具有预定义的属性types,可以使用它们(编写一个通用电话号码,并让它们创build任何#号 – 这在一个很好的规范化系统中是微不足道的,并保持灵活性和完整性!)
如果你有一个非常好的开发团队,并且密切关注你需要用这个devise克服的问题,你可以成功地devise一个devise良好的,而不是非常错误的系统。 大多数时候。
不过,为什么要开始把这些可能性叠加在一起呢?
不要相信我? 谷歌“一个真正的查询表”或“单表devise”。 一些好的结果: 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
MSSQL中的强typesxml字段已经为我们工作。
就像其他人所说的,除非你别无select,否则不要这样做。 需要这种情况的一种情况是,如果您正在销售必须允许用户logging自定义数据的现成产品。 我公司的产品属于这一类。
如果你确实需要让你的客户做到这一点,这里有一些提示:
– 创build一个健壮的pipe理工具来执行模式更改,并且不允许以任何其他方式进行这些更改。
– 使之成为pipe理function; 不允许普通用户访问它。
logging每个模式更改的每个细节。 这将帮助您debugging问题,如果客户做了一些愚蠢的事情,它也会给您CYA数据。
如果你能成功地完成这些事情(尤其是第一个),那么你提到的任何架构都可以工作。 我的首选是dynamic更改数据库对象,因为这使您可以在访问存储在自定义字段中的数据时利用DBMS的查询function。 其他三个选项要求您加载大块数据,然后在代码中执行大部分数据处理。
我有一个类似的要求,并决定使用无模式的MongoDB 。
MongoDB(来自“humongous”)是一个用C ++编程语言编写的开源,可扩展,高性能,无模式,面向文档的数据库。 (维基百科)
强调:
- 具有丰富的查询function(可能最接近SQL DB)
- 生产准备(foursquare,sourceforge使用它)
Lowdarks(你需要了解的东西,所以你可以正确使用mongo):
- 没有交易(实际上它有交易,但只在primefaces操作上)
- 这东西在这里: http : //ethangunderson.com/blog/two-reasons-to-not-use-mongodb/
- 耐久性..主要是酸相关的东西
我在一个真正的项目中做了一些:
数据库由一个表格组成,其中一个字段是50个数组。它有一个“单词”索引。 所有的数据都是无types的,所以“字索引”按预期工作。 数字字段被表示为字符,实际的sorting在客户端完成。 (如果需要的话,每个数据types仍然可能有几个数组字段)。
逻辑表的逻辑数据模式被保存在具有不同的表格行“types”(第一个数组元素)的同一数据库中。 它还支持使用相同“types”字段的写入时复制风格的简单版本控制。
优点:
- 您可以dynamic地重新排列和添加/删除列,不需要转储/重新加载数据库。 任何新的列数据都可以在零时间内设置为初始值(虚拟)。
- 碎片是最小的,因为所有的logging和表是相同的大小,有时它会提供更好的性能。
- 所有的表模式都是虚拟的。 任何逻辑模式结构都是可能的(甚至是recursion的或面向对象的)。
- 这对于“一次写入,大部分读取,不删除/标记为已删除”数据(大多数Web应用程序实际上就是这样)是有好处的。
缺点:
- 只用全文索引,不用缩写,
- 复杂的查询是可能的,但是稍有性能下降。
- 取决于您的首选数据库系统是否支持数组和单词索引(它在PROGRESS RDBMS中已经实现)。
- 关系模型只在程序员的脑海中(即只在运行时)。
而现在我正在考虑下一步可能 – 在文件系统级别上实现这样一个数据库。 这可能相对容易。
关系型数据库的关键在于保持数据的安全性和一致性。 一旦你允许用户改变模式,那么你的数据完整性…
如果您的需要是存储异构数据,例如CMS场景,我会build议将XSDvalidation的XML存储在一行中。 当然,你失去了性能和简单的searchfunction,但这是一个很好的折衷恕我直言。
从2016年起,忘记XML! 使用JSON来存储非关系数据包,并将相应types的列作为后端。 您通常不需要通过包内的值进行查询,即使许多当代SQL数据库本身可以理解JSON,这个速度也会很慢。
听起来像你真正想要的是某种“元模式”,一种数据库模式,它能够描述一个灵活的架构来存储实际的数据。 dynamic模式更改很敏感,而不是您想要的,特别是如果用户被允许进行更改。
你不会find比其他任何更适合这个任务的数据库,所以你最好的select就是根据其他标准select一个。 例如,您使用什么平台来托pipe数据库? 用什么语言编写的应用程序? 等等
澄清我的意思是“元模式”:
CREATE TABLE data ( id INTEGER NOT NULL AUTO_INCREMENT, key VARCHAR(255), data TEXT, PRIMARY KEY (id) );
这是一个非常简单的例子,你可能会有一些更具体的需求(希望稍微容易一些),但是这只能说明我的观点。 您应该将数据库模式本身视为在应用程序级别上不可变的; 任何结构性变化都应该反映在数据中(即,该模式的实例化)。
创build2个数据库
- DB1包含静态表,并表示数据的“真实”状态。
- DB2对用户来说是免费的,他们(或者你)将不得不编写代码来从DB1中填充异形表。
我知道问题中提到的模型全部用于生产系统。 在我工作的一所大型大学/教学机构中正在使用相当大的一个。 他们特别使用长的窄表方法来映射由许多不同的数据采集系统收集的数据。
此外,谷歌最近发布了他们的内部数据共享协议,协议缓冲区,通过他们的代码网站作为开源。 build模这种方法的数据库系统将会非常有趣。
检查以下内容:
实体属性值模型
Google协议缓冲区
EAV的方法我相信是最好的方法,但伴随着沉重的代价
维基百科有一个很好的问题空间的概述:
http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model
我知道这是一个古老的话题,但我认为它从来没有失去现实。 我正在开发类似的东西。 这是我的方法。 我使用MySQL,Apache,PHP和Zend Framework 2作为应用程序框架的服务器设置,但它应该与任何其他设置一样。
这是一个简单的实现指南,你可以从这里进一步发展它。
你将需要实现你自己的查询语言解释器,因为有效的SQL将会太复杂。
例:
select id, password from user where email_address = "xyz@xyz.com"
物理数据库布局:
表“规范”:(应该caching在你的数据访问层)
- id:int
- parent_id:int
- 名称:varchar(255)
表'项目':
- id:int
- parent_id:int
- spec_id:int
- data:varchar(20000)
表“规格”的内容:
- 1,0,“用户”
- 2,1,'email_address'
- 3,1,“密码”
表'项目'的内容:
- 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 ) )
您需要将规格表caching在关联数组或哈希表中或类似的东西中,以从规格名称中获取spec_id。 否则,您将需要插入一些更多的SQL开销来从名称中获取spec_id,如下面的代码片段所示:
不好的例子,不要使用这个,避免这个,而是caching规格表!
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" ) )
我希望你明白,并且可以自己判断这种方法对你是否可行。
请享用! 🙂
在过去,我select了选项C – 创build一个“长而窄”的表,该表将dynamic列值存储为行,然后需要对其进行旋转以创build包含特定实体的所有值的“简短”宽行集。 。 但是,我正在使用一个ORM,真的让事情变得很痛苦。 我想不出你会怎么做,比如LinqToSql。 我想我必须创build一个Hashtable来引用这些字段。
@Skliwz:我猜他更感兴趣的是允许用户创build用户定义的字段。
ElasticSearch。 你应该考虑一下,特别是如果你正在处理可以按date分区的数据集,你可以使用JSON来处理数据,而不是使用SQL来检索数据。
ES通过自动提示或者通过一个HTTP命令(“映射”)可以定义/更改的手动来手动推断您发送的任何新的JSON字段的模式。 虽然它不支持SQL,但它有一些很棒的查找function,甚至是聚合。
在c2.com wiki上,探讨了“dynamic关系”的概念。 您不需要DBA:除非您开始添加约束以使其更像传统的RDBMS,否则列和表是“创build写入”:随着项目的成熟,您可以逐步“locking”。
从概念上讲,你可以把每一行看作一个XML语句。 例如,员工logging可以表示为:
<employee lastname="Li" firstname="Joe" salary="120000" id="318"/>
这并不意味着它必须作为XML实现,这只是一个方便的概念化。 如果你要求一个不存在的列,例如“SELECT madeUpColumn …”,它将被视为空白或空(除非增加了约束禁止)。 而且可以使用SQL ,但由于隐含的types模型,必须小心比较。 但除了types处理之外,dynamic关系系统的用户可以感受到在家的感觉,因为他们可以利用大部分现有的RDBMS知识。 现在,如果有人build立它…
sql已经提供了一种方法来改变你的模式:ALTER命令。
只需要一张表格,列出不允许用户更改的字段,并为ALTER写一个不错的界面。