首页 文章

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

提问于
浏览
313

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

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

我认为节省的时间和更简单的代码在我的情况下是值得的,这是一个可辩护的设计选择,还是我应该从一开始就将它标准化?

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

10 回答

  • 7

    是的,那很糟糕 . 我的观点是,如果你不喜欢使用关系数据库,那么寻找一个更适合你的替代方案,有很多有趣的"NOSQL"项目,其中有一些非常先进的功能 .

  • 5

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

    • 无法确保每个值都是正确的数据类型:无法阻止1,2,3,banana,5

    • 无法使用外键约束将值链接到查找表;无法强制执行参照完整性 .

    • 无法强制执行唯一性:无法阻止1,2,3,3,3,5

    • 如果不提取整个列表,则无法从列表中删除值 .

    • 无法存储的列表长度超过字符串列中的列表 .

    • 难以搜索列表中具有给定值的所有实体;你必须使用低效的表扫描 . 可能不得不求助于正则表达式,例如在MySQL中:
      idlist REGEXP '[[:<:]]2[[:>:]]' *

    • 很难计算列表中的元素,或执行其他聚合查询 .

    • 很难将值连接到它们引用的查找表 .

    • 难以按排序顺序获取列表 .

    • 将整数存储为字符串所需的空间大约是存储二进制整数的两倍 . 更不用说逗号字符占用的空间 .

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

    以逗号分隔的列表是错误的,我把它作为我书中的第一章:SQL Antipatterns: Avoiding the Pitfalls of Database Programming .

    有时您需要使用非规范化,但作为@OMG Ponies mentions,这些都是异常情况 . 任何非关系“优化”都会以牺牲其他数据使用为代价来获益,因此请确保您知道哪些查询需要特别对待,以至于它们需要进行非规范化 .


    • MySQL 8.0不再支持这种字边界表达式语法 .
  • 37

    我可能会采取中间立场:将CSV中的每个字段放入数据库中的单独列中,但不要担心规范化(至少目前为止) . 在某些时候,规范化可能会变得有趣,但是将所有数据推到一个列中,您几乎无法从使用数据库中获益 . 您需要将数据分成逻辑字段/列/无论您想要调用它们,然后才能有意义地操作它 .

  • 16

    如果您有固定数量的布尔字段,则可以使用 INT(1) NOT NULL (如果存在则为 BIT NOT NULL )或 CHAR (0) (可为空) . 你也可以使用 SET (我忘了确切的语法) .

  • 0

    一般来说,如果符合项目要求,任何事物都是可以防御的 . 这并不意味着人们会同意或想要捍卫自己的决定......

    通常,以这种方式存储数据不是最理想的(例如,难以进行有效的查询),如果修改表单中的项目,可能会导致维护问题 . 也许你可以找到一个中间地带并使用代表一组位标志的整数代替?

  • 499

    是的,我会说它确实那么糟糕 . 这是一种可辩护的选择,但这并不能使其正确或良好 .

    它破坏了第一个正常形式 .

    第二个批评是将原始输入结果直接放入数据库,而没有任何验证或绑定,这使您对SQL注入攻击持开放态度 .

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

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

  • 37

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

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

    querying an XML list in sql server using Xquery .

    通过作为xml字段,可以解决一些问题 .

    With CSV: 不能确保每个值都是正确的数据类型:无法阻止1,2,3,banana,5

    标签中的 With XML: 值可以强制为正确的类型


    With CSV: 无法使用外键约束将值链接到查找表;无法强制执行参照完整性 .

    With XML: 仍然是一个问题


    With CSV: 无法强制执行唯一性:无法阻止1,2,3,3,3,5

    With XML: 仍然是一个问题


    With CSV: 无法在不提取整个列表的情况下从列表中删除值 .

    With XML: 可以删除单个项目


    With CSV: 很难在列表中搜索具有给定值的所有实体;你必须使用低效的表扫描 .

    With XML: xml字段可以编入索引


    With CSV: 难以计算列表中的元素,或执行其他聚合查询 . **

    With XML: 不是特别难


    With CSV: 很难将值加入到他们引用的查找表中 . **

    With XML: 不是特别难


    With CSV: 难以按排序顺序获取列表 .

    With XML: 不是特别难


    With CSV: 将整数存储为字符串所需的空间大约是存储二进制整数的两倍 .

    With XML: 存储甚至比csv更糟糕


    With CSV: 加上很多逗号字符 .

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


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

  • 12

    好吧,我一直在SQL Server的NTEXT列中使用键/值对选项卡分隔列表已超过4年了,它的工作原理 . 你确实失去了进行查询的灵活性,但另一方面,如果你有一个库来坚持/篡改键值对,那么这不是一个坏主意 .

  • 6

    关于SO的问题有很多问题:

    • 如何从逗号分隔列表中获取特定值的计数

    • 如何从该逗号分隔列表中获取仅具有相同2/3 / etc特定值的记录

    逗号分隔列表的另一个问题是确保值是一致的 - 存储文本意味着拼写错误的可能性......

    这些都是非规范化数据的症状,并突出显示为什么您应该始终为规范化数据建模 . 非规范化可以是查询优化, to be applied when the need actually presents itself .

  • 0

    “一个原因是懒惰” .

    这响起警钟 . 你应该做这样的事情的唯一原因是你知道如何以“正确的方式”做到这一点但你已经得出结论,有一个切实的理由不这样做 .

    话虽如此:如果您选择以这种方式存储的数据是您永远不需要查询的数据,那么可能存在以您选择的方式存储它的情况 .

    (有些用户会对我上一段中的陈述提出异议,说“你永远不知道将来会增加什么要求 . ”这些用户要么被误导,要么说出宗教信仰 . 有时候按照你的要求工作是有利的 . 在你之前 . )

相关问题