小编典典

在数据库列中存储分隔列表真的那么糟糕吗?

all

想象一个带有一组复选框的 Web 表单(可以选择其中任何一个或全部)。我选择将它们保存在一个逗号分隔的值列表中,该列表存储在数据库表的一列中。

现在,我知道正确的解决方案是创建第二个表并正确规范化数据库。实施简单的解决方案更快,我希望快速获得该应用程序的概念验证,而不必花费太多时间。

我认为在我的情况下节省的时间和更简单的代码是值得的,这是一个合理的设计选择,还是我应该从一开始就对其进行规范化?

更多上下文,这是一个小型内部应用程序,它基本上替换了存储在共享文件夹中的 Excel
文件。我也在问,因为我正在考虑清理程序并使其更易于维护。里面有些东西我并不完全满意,其中之一就是这个问题的主题。


阅读 81

收藏
2022-03-22

共1个答案

小编典典

除了由于存储在单个列中的重复值组而违反第一范式之外,逗号分隔的列表还有许多其他更实际的问题:

  • 能不能保证每个值都是正确的数据类型:没办法防止 1,2,3,banana,5
  • 可以使用外键约束将值链接到查找表;没有办法强制参照完整性。
  • 能不能强制唯一性:没办法阻止 1,2,3,3,3,5
  • 可以在不获取整个列表的情况下从列表中删除一个值。
  • 不能存储比字符串列中的长度更长的列表。
  • 难以搜索列表中具有给定值的所有实体;您必须使用低效的表扫描。可能不得不求助于正则表达式,例如在 MySQL:
    idlist REGEXP '[[:<:]]2[[:>:]]'或 MySQL 8.0 中:idlist REGEXP '\\b2\\b'

  • 难以计算列表中的元素,或进行其他聚合查询。

  • 很难将这些值加入到它们引用的查找表中。
  • 很难按排序顺序获取列表。
  • 很难选择保证不会出现在值中的分隔符

为了解决这些问题,您必须编写大量的应用程序代码,重新发明 RDBMS 已经提供的功能更有效

逗号分隔的列表是错误的,因此我将其作为我书中的第一章:SQL
反模式:避免数据库编程的陷阱

有时您需要使用非规范化,但正如提到的,这些是例外情况。任何非关系的“优化”都会以牺牲数据的其他用途为代价来使一种类型的查询受益,因此请确保您知道哪些查询需要特别处理以使其值得去规范化。

关于 SO 的问题有很多:

如何从逗号分隔列表中获取特定值的计数
如何从该逗号分隔列表中获取仅具有相同 2/3/etc 特定值的记录
逗号分隔列表的另一个问题是确保值一致 - 存储文本意味着可能出现拼写错误......

这些都是非规范化数据的症状,并强调了为什么您应该始终为规范化数据建模。非规范化可以是一种查询优化,在实际需要时应用。

2022-03-22