Sar*_*nyu 32 foreign-key database-design
有两个表:Deal和DealCategories。一笔交易可以有多个交易类别。
所以正确的方法应该是制作一个DealCategories具有以下结构的表:
DealCategoryId (PK)
DealId (FK)
DealCategoryId (FK)
Run Code Online (Sandbox Code Playgroud)
但是,我们的外包团队以Deal这种方式将多个类别存储在表中:
DealId (PK)
DealCategory -- In here they store multiple deal ids separated by commas like this: 18,25,32.
Run Code Online (Sandbox Code Playgroud)
我觉得他们这样做是错误的,但我不知道如何清楚地解释为什么这是不对的。
我该如何向他们解释这是错误的?或者也许是我错了,这是可以接受的?
Sim*_*rts 49
是的,这是一个可怕的想法。
而不是去:
SELECT Deal.Name, DealCategory.Name
FROM Deal
INNER JOIN
DealCategories ON Deal.DealID = DealCategories.DealID
INNER JOIN
DealCategory ON DealCategories.DealCategoryID = DealCategory.DealCategoryID
WHERE Deal.DealID = 1234
Run Code Online (Sandbox Code Playgroud)
你现在必须去:
SELECT Deal.ID, Deal.Name, DealCategories
FROM Deal
WHERE Deal.DealID = 1234
Run Code Online (Sandbox Code Playgroud)
然后你需要在你的应用程序代码中做一些事情来将该逗号列表拆分为单独的数字,然后单独查询数据库:
SELECT DealCategory.Name
FROM DealCategory
WHERE DealCategory.DealCategoryID IN (<<that list from before>>)
Run Code Online (Sandbox Code Playgroud)
这种设计反模式源于对关系建模的完全误解(您不必害怕表格。表格是您的朋友。使用它们),或者一种奇怪的误导性信念,即采用逗号分隔的列表并将其拆分会更快在应用程序代码中添加链接表(从来没有)。第三种选择是他们对 SQL 没有足够的信心/能力来设置外键,但如果是这种情况,他们不应该与关系模型的设计有任何关系。
SQL Antipatterns (Karwin, 2010) 用一整章来介绍这个反模式(他称之为“Jaywalking”),第 15-23 页。此外,作者在 SO上发布了一个类似的问题。他指出的关键点(适用于这个例子)是:
COUNT,SUM等),同样,从“复杂”到“几乎是不可能的”变化。询问您的开发人员他们如何为您提供所有类别的列表以及该类别中的交易数量。如果设计得当,那就是四行 SQL。VARCHAR列表长度限制。尽管如果您有一个超过 4000 个字符的逗号分隔列表,那么解析该怪物的速度可能会很慢。TLDR:这是一个从根本上有缺陷的设计,它不会很好地扩展,即使是最简单的查询也会增加额外的复杂性,而且开箱即用它会降低您的应用程序的速度。