多对多关系:在列中使用关联表或分隔值?

时间:2009-04-24 17:50:49

标签: sql database database-design architecture many-to-many

更新2009.04.24

我的问题的主要问题不在于开发人员的混淆以及该怎么做。

关键是要了解分隔值何时是正确的解决方案。

我已经看到商业产品数据库中使用的分隔数据(Ektron lol)。

SQL Server甚至具有XML数据类型,因此可以用于与分隔字段相同的目的。

/ end Update

我正在设计的应用程序有一些多对多的关系。过去,我经常使用关联表来表示数据库中的这些。这给开发人员带来了一些困惑。

这是一个示例数据库结构:

Document
---------------
ID (PK)
Title
CategoryIDs (varchar(4000))


Category
------------
ID (PK)
Title

文档与类别之间存在多对多关系。

在此实现中,Document.CategoryIDs是一个以管道分隔的大型CategoryID列表。

对我来说,这很糟糕,因为它需要在查询中使用子字符串匹配 - 这不能使用索引。我认为这将是缓慢的,不会扩展。

使用该模型,要获取类别的所有文档,您需要以下内容:

select * from documents where categoryids like '%|' + @targetCategoryId + '|%'

我的解决方案是创建一个关联表,如下所示:

Document_Category
-------------------------------
DocumentID (PK)
CategoryID (PK)

这让开发人员感到困惑。是否有一些我缺少的优雅替代解决方案?

我假设Document中会有数千行。类别可能大约40行左右。主要关注的是查询性能。我是否过度设计了这个?

是否存在首选将数据库列存储在数据库列中而不是将数据推送到关联表的情况?

还要考虑我们可能需要在文档之间创建多对多关系。这将建议一个关联表Document_Document。这是首选设计还是将关联的文档ID存储在一个列中更好?

感谢。

9 个答案:

答案 0 :(得分:34)

  

这让开发人员感到困惑。

获得更好的开发者。这是正确的方法。

答案 1 :(得分:25)

您的建议是优雅,强大,最佳实践的解决方案。

由于我不认为其他答案强烈地说了以下内容,我将会这样做。

如果您的开发人员1)无法理解如何在关系数据库中建模多对多关系,并且2)强烈坚持将CategoryID存储为分隔字符数据,

然后他们应该立即失去所有数据库设计权限。至少,他们需要一个真正有经验的专业人士加入他们的团队,他们有权阻止他们做一些不明智的事情,并且可以为他们提供他们完全缺乏的数据库设计培训。

最后,你不应该再次将它们称为“数据库开发人员”,直到它们适当加快速度,因为这对我们这些实际上是有能力的开发人员而言是微不足道的。设计师。

我希望这个答案对你有帮助。

<强>更新

  

我的问题的主要问题不在于开发人员的混淆以及该怎么做。

     

关键是要了解分隔值何时是正确的解决方案。

除极少数情况外,定界值是错误的解决方案。当查询/插入/删除/更新单个值时,这证明这是错误的决定,因为您必须解析并触摸所有其他值才能使用所需的值。通过这样做,你违反了第一个(!!!)正常形式(这句话应该听起来像一个令人难以置信的邪恶的咒骂)。使用XML来做同样的事情也是错误的。在一列中存储分隔的值或者多值XML的可能的制作时,它作为一个不可分割的和不透明的“属性包”,是不是由数据库查询上,但总是发送整个到另一个消费者处理感(可能是Web服务器或EDI收件人)。

这让我回到我最初的评论。认为违反第一范式的开发人员是一个好主意,是我书中缺乏经验的开发人员。

我将授予一些非常复杂的非关系数据存储实现,使用文本属性包(例如Facebook(?)和在数千台服务器上运行的其他数百万用户站点)。好吧,当您的数据库,用户群和每秒事务数量足够大时,您将有足够的资金来开发它。与此同时,坚持最佳实践。

答案 2 :(得分:17)

使用以逗号分隔的ID几乎总是一个大错误 RDBMS旨在存储关系。

答案 3 :(得分:16)

  

我的解决方案是创建一个   关联表如下:这是   让开发人员感到困惑

真的?这是数据库101,如果这让他们感到困惑,那么他们可能需要离开他们向导生成的代码并学习一些基本的数据库规范化。

您的建议是正确的解决方案!!

答案 4 :(得分:11)

设计中的Document_Category表肯定是解决问题的正确方法。如果可能的话,我建议你教育开发人员,而不是提出一个次优的解决方案(并且会受到性能影响,并且没有参考完整性)。

您的其他选项可能取决于您使用的数据库。例如,在SQL Server中,您可以拥有一个XML列,该列允许您将数组存储在预定义的模式中,然后根据该字段的内容进行连接。其他数据库系统可能有类似的东西。

答案 5 :(得分:6)

您正在进行的多对多映射很好并且已标准化。如果需要,它还允许稍后添加其他数据。例如,假设您要添加将类别添加到文档中的时间。

我建议在document_category表上也有一个代理主键。如果有意义的话,还有一个Unique(documentid,categoryid)约束。

为什么开发人员会感到困惑?

答案 6 :(得分:6)

这对开发人员的设计造成了困惑,这意味着你的教育程度不高的开发人员。这是更好的关系数据库设计 - 如果可能的话,你应该使用它。

如果您确实想使用列表结构,请使用了解它们的DBMS。此类数据库的示例是U2(Unidata,Universe)DBMS,它们基于Pick DBMS(或者很久以前)。可能还有其他类似的DBMS提供商。

答案 7 :(得分:5)

这是经典的对象关系映射问题。开发人员可能不是愚蠢的,只是缺乏经验或不习惯以正确的方式做事。大喊“3NF!”一遍又一遍不会说服他们正确的方式。

我建议您让您的开发人员向您解释他们如何使用管道分隔方法按类别获取文档数量。这将是一场噩梦,而链表则非常简单。

答案 8 :(得分:5)

我的开发人员尝试使用“数据库列中逗号分隔的值”方法的首要原因是,他们认为添加新表以满足对多个值的需求将需要很长时间才能添加到数据中模型和数据库。

他们中的大多数人都知道他们的工作因各种原因而不好,但他们选择这种次优的方法是因为他们只能。他们可以做到这一点,也许永远不会被抓住,或者他们会在项目的后期被捕获,因为它太昂贵且风险很大。他们为什么这样做呢?因为他们的表现完全取决于速度,而不是质量或合规性。

在我的一个项目中,也可能是开发人员已经一个表来放置多个值,但是他们认为复制父表中的数据会加速性能。他们错了,他们被叫出来了。

因此,虽然您确实需要一个如何处理这些代价高昂,风险较大且商业信心破坏性技巧的答案,但您也应该尝试找出开发人员认为采用此课程的原因。项目和公司的短期和长期行动都会更好。然后修复感知和数据结构。

是的,它可能只是懒惰,恶意或无知,但我打赌大部分时间开发人员都会这样做,因为他们经常被告知“只是完成它”。我们在数据模型和数据库设计方面需要确保我们不会发送错误的消息,告知我们对满足新实体/表/信息的业务需求的请求的响应能力。

我们还应该看到数据人们需要不断监控数据架构中的“竣工”部分。

就个人而言,我从未授权在关系数据库中使用逗号分隔值,因为构建新表实际上比构建解析例程以创建,更新和管理列中的多个值更快>和处理引入的所有异常,因为有时数据也嵌入了逗号。

最重要的是,不要使用逗号分隔的值,但要找出开发人员想要执行此操作的原因并解决该问题。