是的,这是一个糟糕的主意。
而不是去:
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
您现在必须去:
SELECT Deal.ID, Deal.Name, DealCategories
FROM Deal
WHERE Deal.DealID = 1234
然后,您需要在应用程序代码中进行一些操作,以将该逗号列表拆分为多个数字,然后分别查询数据库:
SELECT DealCategory.Name
FROM DealCategory
WHERE DealCategory.DealCategoryID IN (<<that list from before>>)
这种设计反模式源于对关系建模的完全误解(您不必害怕表。表是您的朋友。使用它们),或者是一种被误导的信念,即用逗号分隔的列表进行拆分会更快在应用程序代码中,它比添加链接表要更是如此(从不)。第三种选择是,他们对SQL没有足够的信心/能力来设置外键,但是如果是这样,他们就应该与关系模型的设计无关。
SQL Antipatterns(Karwin,2010年)在此反模式(他称为“ Jaywalking”)上专门撰写了整整一章,第15-23页。同样,作者在SO上发表了类似问题。他指出的关键点(应用于此示例)是:
- 查询特定类别中的所有交易相当复杂(解决该问题的最简单方法是正则表达式,但正则表达式本身就是一个问题)。
- 没有外键关系,您将无法强制执行参照完整性。如果删除DealCategory nr。#26然后,您必须在应用程序代码中进行每笔交易,以查找对类别#26的引用并将其删除。这是应该在数据层处理的事情,必须在您的应用程序中处理它是很不好的事情。
- 同样,汇总查询(
COUNT
,SUM
等)从“复杂”到“几乎不可能”。询问您的开发人员,他们将如何获得所有类别的列表以及该类别中交易数量的清单。经过适当的设计,这就是SQL的四行。
- 更新变得更加困难(例如,您的交易分为五个类别,但是您想要删除两个类别并添加其他三个类别)。这是经过适当设计的三行SQL。
- 最终,您会遇到
VARCHAR
列表长度限制。尽管如果您有一个超过4000个字符的逗号分隔列表,那么无论如何,解析该怪物的速度都会变得很慢。
- 从数据库中拉出一个列表,将其拆分,然后再返回数据库进行另一个查询,从本质上讲比一个查询要慢。
TLDR:这是一个从根本上存在缺陷的设计,无法很好地扩展,它甚至给最简单的查询都带来了额外的复杂性,而且开箱即用会降低应用程序的速度。