想象一个带有一组复选框的网络表单(可以选择其中的任何一个或全部)。我选择将它们保存在以逗号分隔的值列表中,这些值存储在数据库表的一列中。
现在,我知道正确的解决方案是创建第二个表并正确规范化数据库。实现简单解决方案的速度更快,我想快速获得该应用程序的概念验证,而不必花费太多时间。
我认为节省的时间和更简单的代码在我的情况下是值得的,这是一个合理的设计选择,还是我应该从一开始就规范化它?
更多上下文,这是一个小型内部应用程序,基本上取代了存储在共享文件夹中的 Excel 文件。我问也是因为我正在考虑清理程序并使其更易于维护。里面有些东西我不太满意,其中之一就是这个问题的主题。
最佳答案
除了违反First Normal Form由于重复的一组值存储在单个列中,逗号分隔的列表还有很多其他更实际的问题:
- 无法确保每个值都是正确的数据类型:无法防止 1,2,3,banana,5
- 不能使用外键约束将值链接到查找表;无法强制执行参照完整性。
- 无法强制唯一性:无法防止 1,2,3,3,3,5
- 无法在不获取整个列表的情况下从列表中删除值。
- 列表的存储长度不能超过字符串列的长度。
- 很难在列表中搜索具有给定值的所有实体;您必须使用低效的表扫描。可能不得不求助于正则表达式,例如在 MySQL 中:
idlist REGEXP '[[:<:]]2[[:>:]]'
或者在 MySQL 8.0 中:idlist REGEXP '\\b2\\b'
- 难以统计列表中的元素,或者做其他聚合查询。
- 很难将值连接到它们引用的查找表。
- 很难按排序顺序获取列表。
- 很难选择保证不会出现在值中的分隔符
要解决这些问题,您必须编写大量应用程序代码,重新发明 RDBMS 已经提供的更高效的功能。
以逗号分隔的列表非常错误,以至于我将此作为本书的第一章:SQL Antipatterns, Volume 1: Avoiding the Pitfalls of Database Programming .
有时您需要使用反规范化,但如 @OMG Ponies mentions ,这些是异常(exception)情况。任何非关系“优化”都会以牺牲数据的其他用途为代价使一种类型的查询受益,因此请确保您知道哪些查询需要特别处理以使其值得反规范化。
关于database - 在数据库列中存储分隔列表真的那么糟糕吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58426524/