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

想象一下带有一组checkbox的网页表单(可以select任何一个或全部)。 我select将它们保存在数据库表的一列中存储的逗号分隔值列表中。

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

我认为节省的时间和简单的代码在我的情况下是值得的,这是一个可靠的deviseselect,还是应该从一开始就规范化呢?

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

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

  • 不能确保每个值是正确的数据types:没有办法防止1,2,3,香蕉,5
  • 不能使用外键约束将值链接到查找表; 没有办法强制参照完整性。
  • 不能强制唯一性:没有办法阻止1,2,3,3,3,5
  • 无法从列表中删除一个值而不提取整个列表。
  • 无法存储比列中string长的列表。
  • 很难search列表中给定值的所有实体; 你必须使用低效的表扫描。 可能不得不求助于正则expression式,例如在MySQL中:
    idlist REGEXP '[[:<:]]2[[:>:]]'
  • 很难对列表中的元素进行计数,或者执行其他聚合查询。
  • 很难将这些值join到他们引用的查询表中。
  • 很难按sorting顺序获取列表。
  • 将整数存储为string需要的空间大约是存储二进制整数的两倍。 更不用说逗号字符所占用的空间了。

为了解决这些问题,您必须编写大量的应用程序代码,重新创buildRDBMS 已经提供的function。

逗号分隔的列表是错误的,所以我把它作为我书中的第一章: SQL反模式:避免数据库编程的陷阱 。

有时候你需要使用非规范化,但正如@OMG Ponies所说 ,这些都是例外情况。 任何非关系型的“优化”都会以牺牲数据的其他用途为代价来获得一种types的查询,因此请确保您知道哪些查询需要特别处理,以至于他们应该得到非规范化。

有这么多的问题要问:

  • 如何从逗号分隔列表中获得特定值的计数
  • 如何从那个逗号分隔的列表中获得只有相同2/3等特定值的logging

逗号分隔列表的另一个问题是确保值是一致的 – 存储文本意味着错别字的可能性…

这些都是非规范化数据的所有症状,并强调为什么你应该总是为规范化的数据build模。 非规范化可以是查询优化, 当需求实际出现时可以应用

“其中一个原因是懒惰”。

这响起警钟。 你应该这样做的唯一理由是你知道如何做到“正确的方式”,但是你得出的结论是有一个切实的理由不这样做。

话虽如此:如果您select以这种方式存储的数据是您永远不需要查询的数据,那么可能存在以您select的方式存储的数据。

(有些用户会对我前一段的陈述提出异议,说“你永远不知道将来会增加什么要求”,这些用户要么被误导了,要么表示出宗教信仰,有时候,在你面前。)

一般而言,如果满足项目要求,任何事情都可以辩护。 这并不意味着人们会同意或想要捍卫你的决定。

一般来说,以这种方式存储数据是次优的(例如,难以进行有效的查询),并且如果修改表单中的项目,则可能导致维护问题。 也许你可以find一个中间立场,并用一个代表一组位标志的整数来代替?

是的,我会说这真的很糟糕。 这是一个明智的select,但这并不是正确的或好的。

它打破了第一个正常forms。

第二个批评是,将原始input结果直接放入数据库中,而没有任何validation或绑定,这就让您打开SQL注入攻击。

你所谓的懒惰和缺乏SQL知识是新手所做的东西。 我build议花点时间把它做好,把它看作是学习的机会。

或者保持原样,并学习SQL注入攻击的痛苦教训。

我需要一个多值列,它可以被实现为一个XML字段

它可以根据需要转换为逗号分隔

使用Xquery在sql server中查询XML列表 。

通过成为一个XML字段,可以解决一些问题。

使用CSV:不能确保每个值是正确的数据types:没有办法防止1,2,3,香蕉,5

使用XML:标签中的值可以被强制为正确的types


使用CSV:不能使用外键约束将值链接到查找表; 没有办法强制参照完整性。

使用XML:仍然是一个问题


使用CSV:无法强制唯一性:没有办法阻止1,2,3,3,3,5

使用XML:仍然是一个问题


使用CSV:无法从列表中删除值,而无需提取整个列表。

使用XML:可以删除单个项目


使用CSV:难以search列表中给定值的所有实体; 你必须使用低效的表扫描。

使用XML: xml字段可以被索引


使用CSV:难以统计列表中的元素,或执行其他聚合查询。**

用XML:不是特别难


使用CSV:很难将它们的值join到它们引用的查找表中。**

用XML:不是特别难


使用CSV:难以按sorting顺序获取列表。

用XML:不是特别难


使用CSV:将整数存储为string所需的空间大约是存储二进制整数的两倍。

使用XML:存储比csv更糟糕


使用CSV:加上很多逗号字符。

使用XML:使用标记而不是逗号


简而言之,使用XML解决了分隔列表中的一些问题,并且可以根据需要将其转换为分隔列表

是的,这不好的。 我的观点是,如果你不喜欢使用关系数据库,那么寻找一个更适合你的替代scheme,那里有很多有趣的“NOSQL”项目,有一些真正的高级function。

那么我已经在SQL Server的NTEXT列使用键/值对选项卡分隔列表超过4年,现在它工作。 你失去了查询的灵活性,但另一方面,如果你有一个图书馆坚持/ derpersists关键价值对,那么这不是一个坏主意。

我可能会采取中间立场:将CSV中的每个字段都放到数据库中的一个单独的列中,但不要太担心标准化(至less现在)。 在某种程度上,规范化可能会变得有趣,但是将所有的数据放在一个列中,实际上从数据库中获益几乎没有任何好处。 你需要将数据分成逻辑字段/列/你想调用它们的任何东西,然后才能有意义地操纵它。