数据库设计 – 如何构建您的实体模型来存储具有不同数据类型的任意键/值数据?

前端之家收集整理的这篇文章主要介绍了数据库设计 – 如何构建您的实体模型来存储具有不同数据类型的任意键/值数据?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我会继续遇到这样的情况:使用每行键/值模型而不是刚性列/字段模型将一组任意数据存储在表中将是有用的.问题是,我想使用正确的数据类型存储值,而不是将所有内容转换为字符串.这意味着我必须选择具有多个可空列的单个表,每个数据类型一个,或一组值表,每个数据类型一个.我也不确定是否应该使用完整的第三个正常表单,并将键分离成一个单独的表,通过值表引用它们,或者如果最好保持简单的方法并存储值表中的字符串键并接受字符串的重复.

旧/坏:

解决方案使得添加附加值在流体环境中是一个痛苦,因为表需要定期修改.

MyTable
============================
ID    Key1    Key2    Key3
int   int     string  date
----------------------------
1     Value1  Value2  Value3
2     Value4  Value5  Value6

单表解决方

解决方案允许通过单个表进行简化.查询代码仍然需要检查空值来确定该字段正在存储的数据类型.也可能需要检查约束来确保只有一个值字段包含非空数据.

DataValues
=============================================================
ID    RecordID    Key    IntValue    StringValue    DateValue
int   int         string int         string         date
-------------------------------------------------------------
1     1           Key1   Value1      NULL           NULL
2     1           Key2   NULL        Value2         NULL
3     1           Key3   NULL        NULL           Value3
4     2           Key1   Value4      NULL           NULL
5     2           Key2   NULL        Value5         NULL
6     2           Key3   NULL        NULL           Value6

多表解决方

解决方案允许更简洁地使用每个表,尽管代码需要事先知道数据类型,因为它需要为每个数据类型查询不同的表.索引可能更简单和更有效率,因为有更少的列需要索引.

IntegerValues
===============================
ID    RecordID    Key    Value
int   int         string int
-------------------------------
1     1           Key1   Value1
2     2           Key1   Value4

StringValues
===============================
ID    RecordID    Key    Value
int   int         string string
-------------------------------
1     1           Key2   Value2
2     2           Key2   Value5

DateValues
===============================
ID    RecordID    Key    Value
int   int         string date
-------------------------------
1     1           Key3   Value3
2     2           Key3   Value6

你如何处理这个问题?哪个解决方案更好?

此外,如果密钥列分隔成一个单独的表,并通过外键引用,或者是否应该保留在值表中,如果由于某些原因导致密钥名称更改,批量更新?

解决方法

首先,关系数据库不是为了存储任意数据而设计的.关系模型的基本原理在于获取有关存储数据性质的规范.

其次,您建议的是实体属性值(EAV)的变体. EAV的问题来自于数据完整性,报告,性能和维护.他们有他们的地位,但它们类似于药物:在有限的数量和狭窄的情况下使用它们可以是有益的;太多会杀了你

针对EAV撰写查询是一种承担.因此,如果要使用EAV,我看到它们的唯一情况是成功的是限制其使用,以便不允许任何人编写用于特定属性过滤的查询.也就是说,没有人会允许写一个类似于AttributeName =’Foo’的查询.这意味着您永远不能过滤,排序,计算,也不能将特定属性放在报表上的特定位置. EAV数据只是一袋分类数据,可以在报告上大量排出,但就是这样.我甚至看到人们将EAVs实现为Xml blob.

现在,如果您使用EAV,因为它只是一个数据块,我将使用单表方法.单表方法的一个重要优点是您可以添加一个检查约束,确保您在IntValue,StringValue或DateValue列中只有一个值.空值不会花费你太多,如果这只是数据,那么它的性能就不会有什么不同.此外,它将使您的查询更简单,您可以使用简单的case语句返回String,Integer或DateValue.

我可以看到多表方法的许多问题,其中最重要的是没有什么可以阻止相同的属性拥有多种类型的值(例如,IntegerValues中的行和StringValues中的一行).另外,要获取数据,您将始终使用三个左连接,这将使您的查询更麻烦地编写.

EAV的成本是纪律和警惕.在任何情况下,您的开发团队都必须遵守纪律,从不针对特定属性编写报告或查询.开发人员将从管理层获得很大的压力,“只是一次”,写出一些特定属性的过滤器.一旦你走下黑暗的道路,永远都会主宰你的发展和维护. EAV必须保持一大堆数据,没有更多.如果您不能在开发团队中保持这种纪律,那么我不会实施EAV.为了避免维护噩梦,我需要任何新的列的规范.一旦用户确实要过滤,计算或将属性放在报表上的特殊位置,该属性必须成为第一类列.如果您能够保持使用纪律,EAV可以很好地让用户存储他们想要的任何信息,并推迟您需要获取数据元素的规范的时间,直到用户以前面提到的方式使用该属性.

猜你在找的MsSQL相关文章