Database 在数据库列中存储分隔列表真的那么糟糕吗?
假设一个web表单有一组复选框(可以选择其中的任何一个或所有复选框)。我选择将它们保存在以逗号分隔的值列表中,这些值存储在数据库表的一列中 现在,我知道正确的解决方案是创建第二个表并正确地规范化数据库。实现easy解决方案的速度更快,我希望能够快速地证明该应用程序的概念,而不必花费太多时间 我认为在我的情况下,节省的时间和更简单的代码是值得的,这是一个合理的设计选择,还是我应该从一开始就规范化它Database 在数据库列中存储分隔列表真的那么糟糕吗?,database,database-design,database-normalization,Database,Database Design,Database Normalization,假设一个web表单有一组复选框(可以选择其中的任何一个或所有复选框)。我选择将它们保存在以逗号分隔的值列表中,这些值存储在数据库表的一列中 现在,我知道正确的解决方案是创建第二个表并正确地规范化数据库。实现easy解决方案的速度更快,我希望能够快速地证明该应用程序的概念,而不必花费太多时间 我认为在我的情况下,节省的时间和更简单的代码是值得的,这是一个合理的设计选择,还是我应该从一开始就规范化它 更详细地说,这是一个小型的内部应用程序,基本上可以替换存储在共享文件夹中的Excel文件。我这样问也
更详细地说,这是一个小型的内部应用程序,基本上可以替换存储在共享文件夹中的Excel文件。我这样问也是因为我正在考虑清理程序,使其更易于维护。有一些事情我并不完全满意,其中之一就是这个问题的主题。是的,我想说它真的很糟糕。这是一个合理的选择,但这并不意味着它是正确的或好的 它打破了第一范式 第二个批评是,将原始输入结果直接放入数据库,而不进行任何验证或绑定,会使您容易受到SQL注入攻击 你称之为懒惰和缺乏SQL知识的东西是由新手组成的。我建议花点时间把它做好,并把它看作是一个学习的机会
或者让它保持原样,从SQL注入攻击中吸取惨痛的教训。好吧,我在SQL Server中的一个NTEXT列中使用了一个键/值对选项卡分隔列表已经有4年多了,现在它可以工作了。您确实失去了进行查询的灵活性,但另一方面,如果您有一个库可以持久化/删除键值对,那么这不是一个坏主意。有很多问题要问:
- 如何从逗号分隔列表中获取特定值的计数
- 如何从逗号分隔的列表中获取仅具有相同2/3/etc特定值的记录
这些都是非规范化数据的症状,并强调了为什么您应该始终为规范化数据建模。反规范化可以是一种查询优化,在实际需要时应用我可能会采取中间立场:将CSV中的每个字段都放在数据库中的一个单独的列中,但不必太担心规范化(至少目前如此)。在某种程度上,规范化可能会变得有趣,但由于所有数据都被推到一列中,使用数据库几乎没有任何好处。在对数据进行有意义的操作之前,您需要将数据划分为逻辑字段/列/您想调用的任何内容。一般来说,任何符合项目要求的内容都是可以防御的。这并不意味着人们会同意或想要捍卫你的决定 通常,以这种方式存储数据是次优的(例如,更难进行有效的查询),如果修改表单中的项,可能会导致维护问题。也许你可以找到一个折衷方案,用一个整数来表示一组位标志?“一个原因是懒惰” 这敲响了警钟。你应该这样做的唯一原因是你知道如何“以正确的方式”去做,但你已经得出结论,有一个切实的理由不这样做 话虽如此:如果您选择以这种方式存储的数据是您永远不需要查询的数据,那么可能需要以您选择的方式存储它 (一些用户可能会对我上一段中的说法提出质疑,称“你永远不知道将来会添加什么要求”。这些用户要么被误导,要么陈述了宗教信仰。有时候,按照你面前的要求工作是有利的。)除了由于存储在单个列中的重复值组而导致冲突外,逗号分隔列表还有许多其他更实际的问题:
- 无法确保每个值都是正确的数据类型:无法阻止1、2、3、5
- 不能使用外键约束将值链接到查找表;无法强制引用完整性
- 无法强制唯一性:无法阻止1,2,3,3,5
- 如果不获取整个列表,则无法从列表中删除值
- 存储的列表长度不能超过字符串列中的长度
- 难以搜索列表中具有给定值的所有实体;您必须使用低效的表扫描。可能必须使用正则表达式,例如在MySQL中:
或在MySQL 8.0中:idlist REGEXP'[[::]]'
idlist REGEXP'\\b2\\b'
- 很难计算列表中的元素,或执行其他聚合查询
- 很难将值连接到它们引用的查找表
- 很难按排序顺序获取列表
- 很难选择保证不会出现在值中的分隔符