【发布时间】:2010-12-13 23:38:15
【问题描述】:
我之前从事过一些项目,将字段存储在逗号分隔或竖线分隔的字符串中作为字段,这可能代表选项或类似的东西。我想知道这样做是否被认为是糟糕的数据库设计,应该始终使用关系表,或者有时以这种方式存储数据是否可以接受?
【问题讨论】:
-
请参阅stackoverflow.com/questions/1689728/… 了解这可能出错的一些示例。
标签: database-design
我之前从事过一些项目,将字段存储在逗号分隔或竖线分隔的字符串中作为字段,这可能代表选项或类似的东西。我想知道这样做是否被认为是糟糕的数据库设计,应该始终使用关系表,或者有时以这种方式存储数据是否可以接受?
【问题讨论】:
标签: database-design
通常,这是一个坏主意。
但是,规范化和性能之间存在平衡。
如果列表没有被解析并且只是按原样显示,那么最好存储逗号分隔的列表,但是如果列表是针对单个元素进行解析的,您应该坚持使用normalized database schema。
【讨论】:
这取决于你。数据库字段应包含原子数据,即整个值有意义但部分值没有意义。例如,我可能决定将一个人的姓名存储在名为 fullname 的字段中,因此值是 John Smith 和 Mary Jane 等。
这是正确的,如果我将永远将这些值视为一个整体,并且永远不需要只选择名字或只选择姓氏,或按姓氏等排序。
如果姓氏或名字对我有意义,也许我必须在查询中按姓氏排序,然后我将创建两个字段 firstname 和 lastName。
在您的情况下,如果分隔的项目在数据库级别不感兴趣,那么将它们保留在单个字段中就可以了。但是,如果您需要按分隔项进行查询,则将它们拆分为各自的字段。
【讨论】:
就个人而言,我会通过两种方式来解决这个问题:
如果可行,我只需将该逗号/管道分隔列表转换为外键实现并将该数据存储在另一个表中。如果您要处理大量数据,这可能会有缺点,但在大多数情况下它可以工作,如果您打算按这些字段进行查询,您通常希望走这条路。
另一种方法是简单地将数据作为序列化对象存储在数据库中,而不是分隔列表。例如,在 Python 中,您可以使用 pickle 模块序列化标准对象,然后将其存储在数据库中,而不必担心代码执行和其他可能发生的讨厌的黑客攻击。
【讨论】:
如果您发现越来越需要使用存储在字符串中的值在其他表中进行搜索,那么您应该考虑根据其他人的建议对您的数据库进行规范化。 Drupal、Wordpress 等将基本信息存储在字符串中,并且可以正常工作。
【讨论】:
这取决于 - 如果数据库不需要对分隔字符串中的数据进行任何类型的过滤或排序,并且数据最初以分隔格式发送到数据库,为什么不呢?如果数据库永远不会使用它,为什么还要麻烦解析并将其拆分为单独的字段?
【讨论】:
它通常被认为是不好的,因为它违背了拥有数据库的目的(以及它强大的索引和搜索数据的方法)。但是,可以根据具体情况进行论证。如果已经对分隔字符串进行了处理,并且除了检索它之外你不想对结构做任何事情......谁来阻止你?
【讨论】:
这不是关系。
例如,如果你有这个:
abc | 123,456,789
def | 123
ghi | 123
把它归一化成这样:
1 | abc | 123
2 | abc | 456
3 | def | 123
4 | ghi | 123
5 | abc | 789
【讨论】:
就像所有优秀的设计问题一样,答案应该是“视情况而定”。关系数据库中的一列旨在提供一个离散的逻辑信息单元,可用于表征数据。我想说,如果永远没有任何理由通过列的内容来表征两个不同的数据——也就是说,你永远不想根据列的内容找到一些数据而不是其他数据——没关系。
例如,如果您将文件权限数据存储在列中,并且仅保留数据以存储文件的权限以便以后可以读取,那么就可以了。如果您想查询具有 u+x 权限的文件,这是该列中数据的一个组成部分,您应该将数据分隔到不同的列中。
【讨论】:
这可能是件好事。我曾使用过几个使用数据库表来记录 SOAP 请求和响应的系统。尝试规范化所有这些数据将是非常丑陋的。逗号分隔的列表可能存在类似情况。
【讨论】:
我会避免将分隔字符串放在数据库字段中。一个字段应该始终只保存一个值。这提供了更大的灵活性,并允许您将数据库的内置功能用于大量聚合和其他功能:
例如,假设您有一个书籍和作者数据库(常用于数据库书籍)
可能性(几乎)是无穷无尽的。但是,如果一个字段通过使用分隔符保存多个值,那么每次您需要这些基本函数的答案时都需要解析该字段。
【讨论】:
重要的是要记住,数据库是为了满足应用程序的需求而存在的,不是相反。如果您的应用需要存储以竖线分隔的数据列表,那就这样吧。
我构建的一个管理工具就是一个很好的例子。我需要针对大量关系数据的版本控制功能。我已经有了将所述数据序列化到 JSON 和从 JSON 序列化的例程,因此我创建了一个新的“版本”表,其中包含每个版本的一些标题信息和一个存储 JSON 版本的文本字段。编辑器还包括一个“激活”按钮,用于反序列化和规范化数据,并将其放置在单独的表格中,以便主应用程序可以访问它的核心内容。请注意,主应用程序永远不会修改此数据。
虽然我可以在此架构中的每个表中添加一个“version_id”字段,并为我的所有存储过程添加一个相应的参数,但它会无缘无故地创建工作。
不要过度使用这种方法。从技术上讲,将整个数据库存储在一个字段中是可行的,但这几乎是不可取的或效率不高的。
【讨论】:
正如其他人所说,通常最好对数据进行规范化,以便可以轻松访问和更新它,但可能存在这样做没有优势的特殊情况。
我要提防的是“过早优化”的心态,其中设计人员假设将数据保存在规范化表中对性能不利,但实际上并没有证明这一点。我经常使用数据库,其中一些信息(例如,用户拥有的角色列表)已连接到单个字符串中。我几乎总是发现,出于好奇,我构建数据的规范化版本并对其进行基准测试时,它的性能至少与“非规范化性能”版本一样。
【讨论】:
如果您要存储项目的快照并希望返回查看当时选择了哪些选项,我可以看到将这样的值存储到一个字段中。我曾在一个单一字段存储一个大型 XML 文件的位置工作,该文件代表一张被引用为历史文档的发票。
尽管在日常使用中使用这种类型的方法并不简单,也不会像许多其他答案所述的那样有用。
【讨论】:
虽然这个问题很老,但我必须说我现在的经历非常艰难,因为我必须在后端使用分隔字符串。我同意关于这个问题的大多数帖子,因为它确实取决于应用程序的需求,但还必须考虑的是后端的需求,这意味着那些以后可能实际上必须使用数据的人。正如文森特所说,如果您打算进行报告,或者以后以某种方式使用您为某种目的而存储的数据,那么通常您会希望确保避免让自己或任何可能使用数据的人变得更加困难.如果您担心的只是存储它,那么做任何让您开心的事情。
【讨论】: