数据库设计:在数据库中保留分隔字符串是不好的

Database Design: Is it bad to keep delimited strings in a database

本问题已经有最佳答案,请猛点这里访问。

之前我曾在项目上工作,将字段存储在逗号分隔或管道分隔的字符串中作为字段,这可能代表选项或类似的东西。 我想知道这样做是否被认为是错误的数据库设计,应该始终使用关系表,或者有时以这种方式存储数据是否可以接受?


通常,这是一个坏主意。

但是,在标准化和性能之间存在平衡。

如果列表未被解析并且只是按原样显示,那么最好存储以逗号分隔的列表,但如果为单个元素解析列表,则应该坚持使用规范化的数据库模式。


这取决于你。数据库字段应该包含原子数据,也就是说,整个值是有意义的,但值的一部分不是。例如,我可能决定将一个人的名字存储在名为fullname的字段中,因此值为John Smith和Mary Jane等。

这是正确的,如果我将永远将这些值视为一个整体,并且永远不需要仅选择名字或姓氏,或按姓氏排序等。

如果姓氏或名字对我有意义,也许我必须在查询中按姓氏排序,那么我将创建两个字段firstname和lastName。

在您的情况下,如果分隔的项目在数据库级别不感兴趣,那么可以将它们保存在单个字段中。但是,如果您需要通过分隔项进行查询,则将它们拆分为各自的字段。


如果您发现越来越需要使用存储在字符串中的值来在其他表中进行搜索,那么您应该考虑按照其他人的建议对数据库进行规范化。 Drupal,Wordpress等将基本信息存储在字符串中,并且它可以正常工作。


就个人而言,我会以两种方式处理:

  • 如果可行,我只需将该逗号/管道分隔列表转换为外键实现,并将该数据存储在另一个表中。如果您处理大量数据,这可能会有缺点,但在大多数情况下它可以工作,如果您打算通过这些字段进行查询,您通常希望采用这种方式。

  • 另一种方法是简单地将数据存储为数据库中的序列化对象,而不是分隔列表。例如,在Python中,您可以使用pickle模块来序列化标准对象,您可以将其存储在数据库中,而无需担心代码执行和可能发生的其他讨厌的黑客攻击。


虽然这个问题很老,但我必须说我现在有一个非常艰难的经历,因为我必须在后端使用分隔字符串。我同意这个问题上的大多数帖子,因为它确实取决于应用程序的需求,但是还必须考虑后端的需求,这意味着那些可能实际上必须在以后使用这些数据的人。正如文森特所说,如果您计划进行报告,或以某种方式使用您以后出于某种目的存储的数据,那么通常您需要确保避免让自己更难或者使用数据的人更难。如果您只是担心存储它,那么做任何让您开心的事情。


如果您正在存储项目的快照并希望返回并查看当时选择了哪些选项,我可以看到将这样的值存储到一个字段中。我曾经在一个单独的字段存储一个大型XML文件的位置工作,该文件重新处理了作为历史文档引用的发票。

对于日常使用而言,使用这种类型的方法并不是简单的,也不是很有用的,如许多其他答案所述。


正如其他人所说,通常最好将数据标准化,以便可以轻松访问和更新,但可能存在这样做的例外情况。

我要提醒的是"过早优化"的思维方式,设计者认为在规范化表中保存数据对性能不利,而不是实际证明这一点。我经常使用数据库,其中一些信息(例如,用户拥有的角色列表)已连接成一个字符串。我几乎总是发现,出于好奇,我构建数据的规范化版本并对其进行基准测试时,它至少与"非规范化性能"版本一样好。


重要的是要记住,数据库可以满足应用程序的需求,而不是相反。如果您的应用需要存储管道分隔数据列表,那就这样吧。

一个很好的例子是我建立的管理工具。我需要大量关系数据的版本控制功能。我已经有了将所述数据序列化到JSON和来自JSON的例程,所以我创建了一个新的"版本"表,其中包含每个版本的一些头信息和一个存储JSON版本的文本字段。编辑器还包括一个"激活"按钮,用于反序列化和规范化数据,并将其放在单独的表中,以便主应用程序可以访问它的内容。请注意,主应用程序永远不会修改此数据。

虽然我本可以在此模式中的每个表中添加"version_id"字段,并为我的所有存储过程添加了相应的参数,但它本来就没有充分的理由创建工作。

只是不要过分采用这种方法。从技术上讲,将整个数据库存储在一个字段中是可能的,但这几乎不可取或不高效。


这可能是件好事。我使用过几个使用数据库表来记录SOAP请求和响应的系统。尝试规范化所有数据将是非常难看的。逗号分隔列表可能存在类似情况。


像所有好的设计问题一样,答案应该是"它取决于"。关系数据库中的列旨在提供可用于表征数据的一个离散逻辑信息单元。我会说,如果根据列的内容永远没有任何理由来表征两个不同的数据 - 也就是说,你根本不想根据列的内容找到一些数据而不是其他数据 - 这没关系。

例如,如果您在列中存储文件权限数据,并且只保留数据以存储文件的权限以便以后可以读取,那么就可以了。如果您想查询具有u + x权限的文件(该列是该列中数据的一个组件),则应将数据分隔到不同的列。


它不是关系型的。

例如,如果你有这个:

1
2
3
abc | 123,456,789
def | 123
ghi | 123

将其标准化为以下内容:

1
2
3
4
5
1 | abc | 123
2 | abc | 456
3 | def | 123
4 | ghi | 123
5 | abc | 789


我会避免在数据库字段中放置分隔的字符串。字段应始终只包含一个值。这样可以提供更大的灵活性,并允许您使用数据库的内置功能来实现大量聚合和其他功能:

例如,假设您有一个书籍和作者数据库(通常用于数据库书籍)

  • 获得每位作者的书籍数量
  • 添加或删除作者的单本书
  • 获得所有作者的书籍总数
  • 可能性(几乎)无穷无尽。但是如果一个字段通过使用分隔符持有多个值,则每次需要对这些基本函数的任何答案时,都需要解析该字段。


    它通常被认为是不好的,因为它破坏了拥有数据库的目的(及其强大的索引和搜索数据的方法)。但是,它可以根据具体情况进行调整。如果已经为分隔的字符串进行了处理,并且你永远不想对结构做任何事情而不是检索它...谁会阻止你?


    这取决于 - 如果数据库不需要对分隔字符串中的数据进行任何类型的过滤或排序,并且数据最初是以分隔格式发送到数据库的,为什么不呢?如果数据库永远不会使用它,为什么要解析并将其拆分为单独的字段呢?