如何为用户定义的字段devise数据库?
我的要求是:
- 需要能够dynamic添加任何数据types的用户定义字段
- 需要能够快速查询UDF
- 需要能够根据数据types对UDF进行计算
- 需要能够根据数据types对UDF进行sorting
其他信息:
- 我正在寻找性能
- 有几百万个Masterlogging可以附带UDF数据
- 上次检查时,我们目前的数据库中有超过5000万个UDFlogging
- 大多数情况下,UDF只附加在几千条主logging上,而不是全部
- UDF不被连接或用作键。 他们只是用于查询或报告的数据
选项:
-
用StringValue1,StringValue2 … IntValue1,IntValue2 …等创build一个大表。我讨厌这个想法,但会考虑,如果有人可以告诉我,它比其他想法和原因好。
-
创build一个dynamic表格,根据需要添加新的列。 我也不喜欢这个想法,因为除非你为每一列编制索引,否则性能会很慢。
-
创build一个包含UDFName,UDFDataType和Value的表。 当一个新的UDF被添加时,生成一个视图,只拉取这些数据,并将其parsing成指定的types。 不符合parsing条件的项目返回NULL。
-
创build多个UDF表,每个数据types一个。 所以我们有UDFStrings,UDFDates等表。可能会做同样的#2和自动生成一个视图任何时候添加一个新的字段
-
XML数据types? 之前我没有和他们合作过,但是看过他们提到过。 不知道他们是否会给我我想要的结果,尤其是在performance方面。
-
别的东西?
如果性能是主要关注的话,我会用#6 … UDF(真的,这是#2的一个变种)表。 这个答案是专门针对这种情况和描述的数据分布和访问模式。
优点:
-
因为您指出某些UDF具有整个数据集的一小部分的值,所以单独的表将会为您提供最佳的性能,因为该表只会支持UDF所需的大小。 相关指数也是如此。
-
通过限制聚合或其他转换需要处理的数据量,也可以提高速度。 将数据拆分成多个表格,可以对UDF数据执行一些聚合和其他统计分析,然后通过外键将该结果连接到主表以获取非聚合属性。
-
您可以使用反映数据实际内容的表/列名称。
-
您可以完全控制使用数据types,检查约束,默认值等来定义数据域。 不要低估即时数据types转换的性能。 这些约束还有助于RDBMS查询优化器制定更有效的计划。
-
如果您需要使用外键,则基于触发器或应用程序级别约束实施很less会执行内置的声明式参照完整性。
缺点:
-
这可能会创build很多表格。 实施模式分离和/或命名约定可以缓解这一点。
-
运行UDF定义和pipe理需要更多的应用程序代码。 我期望这比原来的选项1,3和4更less的代码。
其他注意事项:
-
如果关于数据的性质有任何关于UDF被分组的意义,那就应该鼓励。 这样,这些数据元素可以合并成一个表格。 例如,假设您有颜色,尺寸和成本的UDF。 数据的趋势是这个数据的大部分情况是这样的
'red', 'large', 45.03
而不是
NULL, 'medium', NULL
在这种情况下,通过组合1个表中的3列,不会产生明显的速度损失,因为less数值将为NULL,并且避免再增加2个表,这就是当您需要访问全部3列。
-
如果你从一个人口稠密且经常使用的UDF中select性能墙,那么应该考虑将它包含在主表中。
-
逻辑表devise可以把你带到某个特定的地方,但是当logging数量真的很大时,你也应该开始关注你所select的RDBMS提供的表分区选项。
我已经写 了很多这个问题。 最常见的解决scheme是Entity-Attribute-Value反模式,这与您在选项#3中描述的类似。 避免像鼠疫这样的devise 。
当我需要真正dynamic的自定义字段时,我使用这个解决scheme的方法是将它们存储在一个XML块中,这样我可以随时添加新的字段。 但为了使其更迅速,还需要为每个需要search或sorting的字段创build附加的表(每个字段不包含表 – 每个可search字段只有一个表)。 这有时被称为倒排索引devise。
您可以在这里阅读2009年关于这个解决scheme的一篇有趣的文章: http : //backchannel.org/blog/friendfeed-schemaless-mysql
或者你也可以使用一个面向文件的数据库,在这个数据库中,每个文档都有自定义字段。 我会selectSolr 。
我很可能会创build一个如下结构的表格:
- varchar名称
- varchartypes
- 十进制NumberValue
- varchar StringValue
- dateDateValue
确切的课程types取决于你的需求(当然还有你正在使用的dbms)。 你也可以在int和booleans中使用NumberValue(decimal)字段。 您也可能需要其他types。
您需要链接到拥有该值的主logging。 为每个主表创build一个用户字段表并添加一个简单的外键可能是最简单也是最快的。 通过这种方式,您可以方便快捷地按用户字段过滤主logging。
你可能想要一些元数据信息。 所以你最终得到以下结果:
表UdfMetaData
- int id
- varchar名称
- varchartypes
表MasterUdfValues
- int Master_FK
- int MetaData_FK
- 十进制NumberValue
- varchar StringValue
- dateDateValue
无论你做什么,我都不会dynamic地改变表格结构。 这是一个维修噩梦。 我也不会使用XML结构,它们太慢了。
这听起来像是一个可以通过非关系解决scheme(如MongoDB或CouchDB)更好地解决的问题。
它们都允许dynamic模式扩展,同时允许您维护您寻求的元组完整性。
我同意比尔·卡尔文(Bill Karwin)的观点,EAV模型对你来说并不是一个高效的方法。 在关系系统中使用名称 – 值对本质上并不坏,但是只有当名称 – 值对构成一个完整的信息元组时才能很好地工作。 在使用它的时候强迫你在运行时dynamic地重build一个表,所有的东西开始变得很难。 查询成为枢轴维护中的一个练习,或迫使您将元组重构向上推入对象层。
如果没有在对象层中embedded模式规则,则无法确定空值或缺失值是否是有效条目或缺less条目。
你失去了有效pipe理你的模式的能力。 一个100字符的varchar是“value”字段的正确types吗? 200字? 应该是nvarchar而不是? 这可能是一个难以取舍的问题,最后一个问题就是你必须对你的设置的dynamic性进行人为的限制。 就像“你只能有x个用户定义的字段,每个只能是y个字符长。
使用面向文档的解决scheme(如MongoDB或CouchDB),您可以在单个元组中维护与用户关联的所有属性。 既然join不是问题,生活是快乐的,因为尽pipe有炒作,这两个人都不擅长join。 您的用户可以根据自己的需要定义多个属性(或者您将允许),直到您达到4MB左右为止。
如果您的数据需要ACID级别的完整性,则可以考虑拆分解决scheme,使用关系数据库中的高完整性数据和处于非关系存储中的dynamic数据。
即使您提供了添加自定义列的用户,查询这些列的情况也不一定会很好。 查询devise有许多方面可以使它们performance良好,其中最重要的是对什么应该存储在首位的正确规范。 因此,从根本上来说,是不是允许用户创build模式而不考虑规范,并且能够从该模式中快速获取信息? 如果是这样,那么任何这样的解决scheme都可以很好地扩展,尤其是如果你想允许用户对数据进行数值分析的话。
选项1
海事组织这种方法给你架构没有知识的模式意味着什么是灾难的食谱和报告devise师的噩梦。 也就是说,您必须具有元数据才能知道哪列存储了哪些数据。 如果这个元数据搞砸了,它就有可能挖掘你的数据。 另外,它可以很容易地把错误的数据放在错误的列中。 (“什么?String1包含修道院的名字?我认为这是Chalie Sheen最喜欢的药物。”)
选项3,4,5
IMO的要求2,3和4消除了EAV的任何变化。 如果你需要对这些数据进行查询,sorting或者计算,那么一个EAV是Cthulhu的梦想,你的开发团队和DBA的噩梦。 EAV将在性能方面造成瓶颈,并且不会为您提供所需的数据完整性以快速获取所需的信息。 查询将很快转向交叉表戈比结。
选项2,6
这确实留下了一个select:收集规范,然后构build模式。
如果客户希望在他们希望存储的数据上获得最佳性能,那么他们需要经历与开发人员合作的过程,以了解他们的需求,从而尽可能高效地存储数据。 它仍然可以存储在一个与其余表格分开的表格中,代码可以根据表格的模式dynamic构build一个表格。 如果你有一个允许在列上扩展属性的数据库,甚至可以使用这些数据库来帮助表单生成器使用漂亮的标签,工具提示等,这样所有必要的就是添加模式。 无论哪种方式,要有效地构build和运行报表,数据需要被正确存储。 如果有问题的数据会有大量的空值,那么一些数据库就有能力存储这种types的信息。 例如,SQL Server 2008有一个名为Sparse Columns的特性,专门用于有很多空值的数据。
如果这只是一个没有分析,过滤或sorting的数据包,那么我会说一些EAV的变化可能会起作用。 但是,根据您的要求,即使将这些新列存储在单独的表中,并在这些表中dynamic构build表单,最有效的解决scheme也将是获得适当的规范。
稀疏的列
- 创build多个UDF表,每个数据types一个。 所以我们有UDFStrings,UDFDates等表。可能会做同样的#2和自动生成一个视图任何时候添加一个新的字段
根据我的研究,基于数据types的多个表不会帮助你的performance。 特别是如果你有大量的数据,比如20K或25K的logging有50个以上的UDF。 performance最糟糕。
你应该像下面这样使用多列:
varchar Name varchar Type decimal NumberValue varchar StringValue date DateValue
这是一个有问题的情况,没有一个解决scheme显得“正确”。 然而,就简单性和性能而言,选项1可能是最好的。
这也是一些商业企业应用中使用的解决scheme。
编辑
另一个选项是现在可用,但不存在(或至less是不成熟),当问题是原来的要求是在DB中使用json字段。
许多关系数据库现在支持基于json的字段(可以包含子字段的dynamic列表)并允许查询它们
postgress
MySQL的
我已经有了一些经验,或者是第一,第三和第四,他们最终都是混乱的,不清楚数据是什么,或者真的很复杂,有些软分类将数据分解成dynamictypes的logging。
我会试图尝试XML,你应该能够强制模式对XML的内容来检查数据types等,这将有助于持有不同的UDF数据集。 在较新版本的SQL Server中,您可以在XML字段上进行索引,这将有助于提高性能。 (例如参见http://blogs.technet.com/b/josebda/archive/2009/03/23/sql-server-2008-xml-indexing.aspx )
如果您使用SQL Server,请不要忽略sqlvarianttypes。 这很快,应该做你的工作。 其他数据库可能有类似的东西。
由于性能原因,XML数据types不太好。 如果你在服务器上进行计算,那么你总是不得不反序列化这些。
选项1听起来不好,看起来很糟糕,但性能明智可以是你最好的select。 我之前创build了名为Field00-Field99的表格,因为您无法击败performance。 您可能还需要考虑您的INSERT性能,在这种情况下,这也是您需要的。 如果你想让它看起来整洁,你总是可以在这张桌子上创build视图。
SharePoint使用选项1并具有合理的性能。
在评论中,我看到你说UDF字段是转储导入的数据,用户不正确映射。
也许另一个select是跟踪每个用户所做的UDF数量,并强制他们重复使用字段,说他们可以使用6个(或其他同样随机的限制)自定义字段顶部。
当你遇到像这样的数据库结构化问题时,通常最好回到应用程序的基本devise(在你的案例中是导入系统),并在其上加上一些限制。
现在我要做的是选项4(编辑),并添加一个链接到用户:
general_data_table id ... udfs_linked_table id general_data_id udf_id udfs_table id name type owner_id --> Use this to filter for the current user and limit their UDFs string_link_id --> link table for string fields int_link_id type_link_id
现在确保提出意见来优化性能,并使您的索引正确。 这种标准化级别使数据库占用空间更小,但应用程序更复杂。
我以前使用这些选项都不成功(选项6?:))。
我为用户创build了一个模型(存储为xml并通过自定义build模工具公开),以及从模型生成的表和视图中使用用户定义的数据表连接基表。 因此,每种types都有一个包含核心数据的基表和一个包含用户定义字段的用户表。
以文档为例:典型的字段将是名称,types,date,作者等。这将在核心表中。 然后用户将自己的字段定义自己的特殊文档types,如contract_end_date,renewal_clause,等等等等。 对于那个用户定义的文档,将会有核心文档表xcontract表join一个公共主键(因此xcontracts主键在核心表的主键上也是外部的)。 然后我会生成一个视图来包装这两个表。 查询的速度很快。 额外的业务规则也可以embedded到视图中。 这对我来说真的很好。