Mat*_*man 11 c# sql enums bit-manipulation
RDBMS中的适当规范化意味着表的扩散.整数字段可以将正交数据存储为位 - 这可以用作替代附加表,而不会牺牲关系完整性吗?
Mat*_*man 10
对于一对多的关系,其中"多"具有小数目的已知值的,关系可以被存储为在父表为一个整数位掩码,替换为另一个表的需要.
假设我们有一个表人员,我们想知道一个人访问了多少个大陆.我们首先为每个大陆分配一个"正交"比特值.在C#中,枚举是一个很好的选择:
[Flags]
public enum JobAdvertisingRegion
{
NorthAmerica = 1, // or 1 << 0
SouthAmerica = 2, // 1 << 1
Europe = 4, // 1 << 2
Asia = 8, // 1 << 3
Africa = = 16, // 1 << 4
Australia = 32, // 1 << 5
Anarctica = 64 // 1 << 6
}
Run Code Online (Sandbox Code Playgroud)
然后,Persons表可以只有一个名为Contintents的int列.表明某人已访问过欧洲和亚洲:
UPDATE Persons SET Continents = (4 + 8) WHERE Id = whatever
Run Code Online (Sandbox Code Playgroud)
要搜索访问过南极洲的人员,我们使用按位数学:
SELECT * FROM Persons WHERE Continents & 64 = 64
Run Code Online (Sandbox Code Playgroud)
搜索访问过非洲和亚洲的人员:
SELECT * FROM Persons WHERE Continents & (16 + 8) = (16 + 8)
Run Code Online (Sandbox Code Playgroud)
要搜索访问过澳大利亚或南美洲的人员:
SELECT * FROM Persons WHERE Continents & (32 + 2) != 0
Run Code Online (Sandbox Code Playgroud)
一个缺点是,虽然整数列在SQL中是可索引的,但它们的位组件却不是.对于上述查询,有些优化可以解决这个问题:
SELECT * FROM Persons WHERE Continents & 64 = 64 AND Continents >= 64
SELECT * FROM Persons WHERE Continents & (16 + 8) = (16 + 8) AND Continents >= (16 + 8)
SELECT * FROM Persons WHERE Continents & (32 + 2) != 0 AND Continents >= 2
Run Code Online (Sandbox Code Playgroud)
你的问题的答案是"不".位字段牺牲了关系完整性,原因很简单,因为数据库中的实体没有相应的表.
也就是说,许多数据库通常通过"位"数据类型提供支持.Mysql具有更强大的支持,具有"set"数据类型.
主要问题是您对集合中的元素一无所知 - 全名是什么,何时添加到数据库中,等等.(枚举可以解决部分命名问题.)此外,集合的大小也是有限的.你可能有一个事物有限的例子.然而,马特的例子相当强调了这里的问题.您可以列出访问过的各大洲.但是,当您切换到访问过的国家时,方法必然会有很大不同,因为国家/地区的数量不再适用于单个"单词".您是否希望您的系统在这方面与各国的处理方式截然不同?您是否希望您的设计决策受到计算机字中32或64位的限制?
最后,您似乎将表的扩散视为一个问题.表的扩散实际上是一种解决方案.有关实体的所有数据都存储在表中,而不是通过系统传播.您可以维护有关实体实例的信息,例如创建实例的时间,实例可能随时间的变化情况等等.只要有人想要一个大陆,就可能会使用"大陆"的实体.
考虑一下系统中发生了什么,两个不同的开发人员决定为各大洲开发自己的位掩码 - 但他们将各大洲的顺序排在不同的位置.使用设计良好的关系数据库(意味着在表定义中显式声明了外键关系),不会出现这种混淆.
| 归档时间: |
|
| 查看次数: |
801 次 |
| 最近记录: |