动态数据模型

时间:2010-01-10 13:46:02

标签: c# asp.net database semantics modeling

我有一个项目在运行时需要特定对象的用户定义属性(让我们说这个例子中的一个人物对象)。该项目将有许多不同的用户(1000 +),每个用户为他们自己的'Person'对象集定义他们自己的唯一属性。

(例如 - 用户#1将有一组已定义的属性,这些属性将应用于此用户拥有的所有人物对象。多达1000个用户,这是应用程序工作的底线最小用户数with。)这些属性将用于查询people对象并返回结果。

我认为这些是我可以使用的方法。我将使用C#(以及任何版本的.NET 3.5或4),并且有一个免费的统治:用于数据存储的内容。 (我有mysql和mssql可用,虽然可以自由使用任何软件,只要它符合要求)

我的评估中是否遗漏了任何内容,或做出了错误的假设?

在这些选择中 - 你会采用什么解决方案?

  1. 混合EAV对象模型。 (使用常规关系模型定义数据库,并为Person表创建一个'property bag'表。)

    下行:每个/查询有很多连接。表现不佳。可以达到查询中使用的联接/表数量的限制。

    我已经敲了一个快速示例,它有一个Subsonic 2.x'esqe接口:

    Select().From().Where  ... etc
    

    生成正确的连接,然后过滤器+在c#中转移返回的数据,以返回使用正确类型化的数据集配置的数据表。

    我还没有加载测试这个解决方案。它基于Microsoft白皮书中的EA建议: SQL Server 2008 RTM Documents Best Practices for Semantic Data Modeling for Performance and Scalability

  2. 允许用户在运行时动态创建/更改对象的表。这个解决方案就是我认为NHibernate在使用动态属性时在后台做的事情,如

    所述

    http://bartreyserhove.blogspot.com/2008/02/dynamic-domain-mode-using-nhibernate.html

    缺点:

    随着系统的增长,定义的列数将变得非常大,并且可能会达到最大列数。如果有1000个用户,每个用户的“人”对象有10个不同的属性,那么我们需要一个包含10k列的表。在这种情况下不可扩展。

    我想我可以允许每个用户使用一个人属性表,但是如果有1000个用户可以启动,那么1000个表加上应用程序中的其他10个用户。

    我不确定这是否可扩展 - 但似乎并非如此。如果我不对,请有人纠正我!

  3. 使用NoSQL数据存储区,例如CouchDb / MongoDb

    根据我的阅读,这些尚未在基于字符串的大型应用程序中得到证实,并且处于开发阶段的早期阶段。如果我在这次评估中不正确,有人可以告诉我吗?

    http://www.eflorenzano.com/blog/post/why-couchdb-sucks/

  4. 使用people表中的XML列存储属性

    缺点 - 没有查询索引,因此需要检索和查询每一列以返回结果集,从而导致查询性能不佳。

  5. 将对象图序列化到数据库。

    缺点 - 没有查询索引,因此需要检索和查询每一列以返回结果集,从而导致查询性能不佳。

  6. berkelyDB的C#绑定

    从我在此处阅读:http://www.dinosaurtech.com/2009/berkeley-db-c-bindings/

      

    伯克利Db肯定证明是有用的,但正如罗伯特指出的那样 - 没有简单的界面。您的整个wOO包装器必须手动编码,并且所有索引都是手工维护的。它比SQL / linq-to-sql困难得多,但这是你为荒谬的速度付出的代价。

    似乎是一个很大的开销 - 但是如果有人能提供一个关于如何在C#中维护索引的教程的链接 - 它可能是一个观众。

  7. SQL / RDF混合。 奇怪我以前没想过这个。与选项1类似,但不是“属性包”表,只是XREF到RDF商店? 查询将涉及两个步骤 - 查询RDF存储以查找正确属性的人员,返回人员对象,并在SQL查询中使用这些人员对象的ID来返回关系数据。额外开销,但可能是一个观众。

5 个答案:

答案 0 :(得分:7)

Windows上的ESENT数据库引擎大量用于这种半结构化数据。一个例子是Microsoft Exchange,它与您的应用程序一样,拥有数千个用户,每个用户可以在其中定义自己的一组属性(MAPI命名属性)。 Exchange使用稍微修改过的ESENT版本。

ESENT具有许多功能,可以满足具有大量元数据要求的应用程序:每个ESENT表可以定义大约~32K列;表,索引和列可以在运行时添加;稀疏列在未设置时不占用任何记录空间;和模板表可以减少元数据本身使用的空间。大型应用程序通常有数千个表/索引。

在这种情况下,您可以为每个用户创建一个表,并在表中创建每用户列,从而在要查询的任何列上创建索引。这与某些版本的Exchange存储其数据的方式类似。这种方法的缺点是ESENT没有查询引擎,所以你必须手工制作你的查询,如MakeKey / Seek / MoveNext调用。

ESENT的托管包装器在这里:

http://managedesent.codeplex.com/

答案 1 :(得分:2)

在EAV模型中,您不必拥有多个连接,因为您可以拥有查询过滤所需的连接。对于结果集,将属性条目作为单独的行集返回。 这就是我们在EAV实施中所做的工作。

例如,查询可能会返回具有扩展属性“Age”>的人员。 18:

属性表:

1        Age
2        NickName

第一个结果集:

PersonID Name
1        John
2        Mary

第二个结果集:

PersonID PropertyID Value
1        1         24
1        2         'Neo'
2        1         32
2        2         'Pocahontas'

对于第一个结果集,您需要'age'扩展属性的内部联接 查询基本的Person对象实体部分:

select p.ID, p.Name from Persons p
join PersonExtendedProperties pp
on p.ID = pp.PersonID
where pp.PropertyName = 'Age'
and pp.PropertyValue > 18 -- probably need to convert to integer here

对于第二个结果集,我们使用PersonExtendedProperties表创建第一个结果集的外部联接,以获取其余的扩展属性。它是一个“狭窄”的结果集,我们不会在sql中转动属性,所以我们不需要多个连接。

实际上,我们对不同类型使用单独的表来避免数据类型转换,使索引的扩展属性易于查询。

答案 2 :(得分:0)

我的建议:

允许将属性标记为可索引。对可索引属性的数量以及每个对象的列有一个小的硬限制。对所有对象中的总列类型有很大的硬性限制。

将索引实现为与主数据表连接的单独表(每个索引一个)(主表具有对象的大型唯一键)。 (然后可以根据需要创建/删除索引表。)

序列化数据,包括索引列,并将索引属性放在其专用索引表中的第一类关系列中。使用JSON而不是XML来节省表中的空间。实施短列名称策略(或长显示名称和短存储名称策略)以节省空间并提高性能。

使用夸克表示字段标识符(但仅在主引擎中保存RAM并加快一些读取操作 - 在所有情况下都不要依赖于夸克指针比较。)

我对你的选择的想法:

1是可能的。性能明显低于未存储的字段ID列。

2对于动态模式更改而言,并非所有数据库引擎都不满意。但如果您的数据库引擎擅长这一点,那么可能是肯定的。

3可能。

4是的,虽然我使用的是JSON。

5似乎只有4个不太优化??

6听起来不错;如果愿意尝试一些新的东西,并且对可靠性和性能感到高兴,但通常会想要采用更主流的技术。我还希望减少协调事务所涉及的引擎数量,以便在这里减少。

编辑:但当然,虽然我已经推荐了一些东西,但这里没有一般的正确答案 - 用您的数据描述各种数据模型和方法,看看哪种方式最适合您的应用。< / p>

修改:更改了上次编辑的措辞。

答案 3 :(得分:0)

假设您有一个限制,N,每个用户可以定义的自定义属性数量;只需在Person表中添加N个额外列。然后有一个单独的表,您可以在其中存储每个用户的元数据,以描述如何为每个用户解释这些列的内容。类似于#1,一旦读入数据,但不需要连接来提取自定义属性。

答案 4 :(得分:0)

对于与您的问题类似的问题,我们使用了“XML列”方法(您的方法调查中的第四个方法)。但是您应该注意到许多数据库(DBMS)支持xml值的索引。

我建议您为Person使用一个表,其中包含一个xml列以及其他常用列。换句话说,使用所有人员记录通用的列设计Person表,并为动态和不同属性添加单个xml列。

我们正在使用Oracle。它支持其xml类型的索引。支持两种类型的索引:1- XMLIndex用于索引元素和xml中的属性,2- Oracle Text Index用于在xml的文本字段中启用全文搜索。

例如,在Oracle中,您可以创建索引,例如:

CREATE INDEX index1 ON table_name (XMLCast(XMLQuery ('$p/PurchaseOrder/Reference' 
  PASSING XML_Column AS "p" RETURNING CONTENT) AS VARCHAR2(128)));
选择查询支持

和xml-query:

SELECT count(*) FROM purchaseorder
  WHERE XMLCast(XMLQuery('$p/PurchaseOrder/Reference'
  PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
  AS INTEGER) = 25;

据我所知,其他数据库如PostgreSQL和MS SQL Server(但不是mysql)支持xml值的索引模型。

另见: http://docs.oracle.com/cd/E11882_01/appdev.112/e23094/xdb_indexing.htm#CHDEADIH