想象一个带有一组复选框的 Web 表单(可以选择其中任何一个或全部)。我选择将它们保存在一个逗号分隔的值列表中,该列表存储在数据库表的一列中。
现在,我知道正确的解决方案是创建第二个表并正确规范化数据库。实施简单的解决方案更快,我希望快速获得该应用程序的概念验证,而不必花费太多时间。
我认为在我的情况下节省的时间和更简单的代码是值得的,这是一个合理的设计选择,还是我应该从一开始就对其进行规范化?
更多上下文,这是一个小型内部应用程序,它基本上替换了存储在共享文件夹中的 Excel 文件。我也在问,因为我正在考虑清理程序并使其更易于维护。里面有些东西我并不完全满意,其中之一就是这个问题的主题。
除了由于存储在单个列中的重复值组而违反第一范式之外,逗号分隔的列表还有许多其他更实际的问题:
难以搜索列表中具有给定值的所有实体;您必须使用低效的表扫描。可能不得不求助于正则表达式,例如在 MySQL: idlist REGEXP '[[:<:]]2[[:>:]]'或 MySQL 8.0 中:idlist REGEXP '\\b2\\b'
idlist REGEXP '[[:<:]]2[[:>:]]'
idlist REGEXP '\\b2\\b'
难以计算列表中的元素,或进行其他聚合查询。
为了解决这些问题,您必须编写大量的应用程序代码,重新发明 RDBMS 已经提供的功能更有效 。
逗号分隔的列表是错误的,因此我将其作为我书中的第一章:SQL 反模式:避免数据库编程的陷阱。
有时您需要使用非规范化,但正如提到的,这些是例外情况。任何非关系的“优化”都会以牺牲数据的其他用途为代价来使一种类型的查询受益,因此请确保您知道哪些查询需要特别处理以使其值得去规范化。
关于 SO 的问题有很多:
如何从逗号分隔列表中获取特定值的计数 如何从该逗号分隔列表中获取仅具有相同 2/3/etc 特定值的记录 逗号分隔列表的另一个问题是确保值一致 - 存储文本意味着可能出现拼写错误......
这些都是非规范化数据的症状,并强调了为什么您应该始终为规范化数据建模。非规范化可以是一种查询优化,在实际需要时应用。