设想一个web表单有一组复选框(可以选择其中的任何一个或所有复选框)。我选择将它们保存在以逗号分隔的值列表中,这些值存储在数据库表的一列中。
现在,我知道正确的解决方案是创建第二个表并正确地规范化数据库。实现这个简单的解决方案更快,而且我希望能够快速地获得该应用程序的概念证明,而不必花费太多时间。
我认为在我的情况下,节省的时间和更简单的代码是值得的,这是一个合理的设计选择,还是我应该从一开始就规范化它?
更详细地说,这是一个小型的内部应用程序,基本上替换了存储在共享文件夹中的excel文件。我问这个问题也是因为我在考虑清理程序,使它更易于维护。其中有些东西我并不完全满意,其中之一就是这个问题的主题。
10条答案
按热度按时间8yparm6h1#
除了由于存储在单个列中的值的重复组而违反第一个范式之外,逗号分隔列表还有许多其他更实际的问题:
无法确保每个值都是正确的数据类型:无法阻止1、2、3、5
不能使用外键约束将值链接到查找表;无法强制引用完整性。
无法强制唯一性:无法阻止1,2,3,3,3,5
如果不获取整个列表,则无法从列表中删除值。
不能存储超过字符串列长度的列表。
难以搜索列表中具有给定值的所有实体;你必须使用低效的表格扫描。可能必须使用正则表达式,例如在mysql中:
idlist REGEXP '[[:<:]]2[[:>:]]'
*很难计算列表中的元素,或者进行其他聚合查询。
很难将值连接到它们引用的查找表。
很难按顺序提取列表。
为了解决这些问题,您必须编写大量的应用程序代码,重新设计rdbms已经提供的功能,使之更加有效。
逗号分隔的列表是错误的,所以我把它作为我的书的第一章:sql反模式:避免数据库编程的陷阱。
有时需要使用非规范化,但正如@omg ponies提到的,这些都是例外情况。任何非关系型的“优化”都会以牺牲数据的其他用途为代价,从而使一种类型的查询受益,因此请确保您知道哪些查询需要进行特殊处理,以便它们值得反规范化。
vwoqyblh2#
我需要一个多值列,它可以实现为一个xml字段
它可以根据需要转换为逗号分隔
使用xquery在sql server中查询xml列表。
作为一个xml字段,可以解决一些问题。
使用csv:无法确保每个值都是正确的数据类型:无法阻止1、2、3、5
使用xml:可以强制标记中的值为正确的类型
使用csv:不能使用外键约束将值链接到查找表;无法强制引用完整性。
使用xml:仍然是个问题
使用csv:无法强制唯一性:无法阻止1、2、3、3、3、5
使用xml:仍然是个问题
使用csv:如果不获取整个列表,则无法从列表中删除值。
使用xml:可以删除单个项
使用csv:难以搜索列表中具有给定值的所有实体;你必须使用低效的表格扫描。
使用xml:xml字段可以被索引
使用csv:难以计算列表中的元素,或进行其他聚合查询**
使用xml:不是特别难
使用csv:很难将值连接到它们引用的查找表**
使用xml:不是特别难
使用csv:很难按排序顺序获取列表。
使用xml:不是特别难
使用csv:将整数存储为字符串需要的空间是存储二进制整数的两倍。
使用xml:存储甚至比csv更糟糕
使用csv:加上许多逗号字符。
对于xml:使用标记而不是逗号
简而言之,使用xml可以解决分隔列表的一些问题,并且可以根据需要转换为分隔列表
qltillow3#
是的,有那么糟。我的观点是,如果你不喜欢使用关系数据库,那么就找一个更适合你的替代方案,有很多有趣的“nosql”项目,其中有一些非常高级的特性。
1dkrff034#
“一个原因是懒惰”。
这敲响了警钟。你应该这样做的唯一原因是你知道如何用“正确的方法”去做,但你已经得出结论,有一个切实的理由不这样做。
话虽如此:如果您选择以这种方式存储的数据是您永远不需要查询的数据,那么就有可能以您选择的方式存储它。
(有些用户会对我上一段的说法提出异议,说“你永远不可能知道将来会增加什么要求”。这些用户要么被误导,要么陈述宗教信仰。有时,按照你面前的要求工作是有利的。)
zzlelutf5#
是的,我想说真的有那么糟糕。这是一个合理的选择,但这并不意味着它是正确的或好的。
它打破了第一范式。
第二个批评是,将原始输入结果直接放入数据库,而不进行任何验证或绑定,会使您容易受到sql注入攻击。
你所说的懒惰和缺乏sql知识是新手们的天性。我建议花点时间好好做,把它看作是一个学习的机会。
或者保持现状,从sql注入攻击中吸取惨痛的教训。
pieyvz9o6#
好吧,我在SQLServer的ntext列中使用键/值对制表符分隔列表已经有4年多了,现在它可以工作了。您确实失去了进行查询的灵活性,但另一方面,如果您有一个持久化/去持久化键值对的库,那么这并不是一个坏主意。
ee7vknir7#
因此有许多问题要问:
如何从逗号分隔的列表中获取特定值的计数
如何从逗号分隔的列表中获取只有相同2/3/etc特定值的记录
逗号分隔列表的另一个问题是确保值的一致性—存储文本意味着可能出现打字错误。。。
这些都是非规范化数据的症状,并强调了为什么您应该始终为规范化数据建模。反规范化可以是一种查询优化,在实际需要时应用。
koaltpgm8#
一般来说,任何符合项目要求的东西都是可以防御的。这并不意味着人们会同意或想要为你的决定辩护。。。
通常,以这种方式存储数据是次优的(例如,更难执行有效的查询),并且如果修改表单中的项,可能会导致维护问题。也许您可以找到一个中间地带,并使用一个整数来表示一组位标志?
kupeojn69#
如果有固定数量的布尔字段,可以使用
INT(1) NOT NULL
(或BIT NOT NULL
如果存在)或CHAR (0)
(可为空)对于每个。你也可以用SET
(我忘了确切的语法)。w7t8yxp510#
我可能会采取中间立场:将csv中的每个字段放在数据库中一个单独的列中,但不必太担心规范化(至少目前是这样)。在某种程度上,规范化可能会变得有趣,但由于所有数据都被推到一个列中,使用数据库几乎没有任何好处。在对数据进行有意义的操作之前,您需要将数据分隔成逻辑字段/列/任何您想调用的内容。