MS SQL:什么更有效?使用联结表或将所有内容存储在varchar中?

时间:2017-11-06 13:43:13

标签: sql-server query-performance sqlperformance junction-table

这是一个简单的问题,我希望得到答案:

我们有一个会员表。每个成员都会练习一项,多项运动或不运动。最初我们(开发人员)创建了一个 [member] 表,一个 [sports] 表和一个 [member_sports] 表,就像我们一样总是这样。

但是我们这里的客户并不喜欢这样,并希望将成员在一个varchar列中练习的所有体育项目存储起来,并用特殊字符分隔。

所以如果:

1 is football
2 is tennis
3 is ping-pong
4 is swimming

我喜欢游泳和乒乓球,我最喜欢的运动将被存储到varchar列中:

x3,x4

现在我们不想走向客户并宣称他的系统不对。我们想要提供支持,证明从 [member_sports] 获取体育的操作比仅仅将字段存储为varchar更有效。

是否有任何文件可以支持我们的索赔?救命啊!

1 个答案:

答案 0 :(得分:1)

询问您的客户是否关心存储准确的信息 1 而不是随机字符串。

然后为他们设置一系列挑战。首先,确保运动信息在正确的“域”中。对于member_sports表,即:

sport_id int not null
         ^
         |--correct type

对于他们“在varchar列中存储所有内容”的解决方案,我猜你正在写一个CHECK约束。正则表达式可能会对此有所帮助,但SQL Server中没有正则表达式的原生支持 - 因此您要么支持它,要么调用CLR函数以确保只存储实际的int值。

接下来,我们不仅要确保域名正确,而且系统中的运动实际上是定义的。对于member_sports,那是:

CONSTRAINT FK_Member_Sports_Sports FOREIGN KEY (Sport_ID) references Sports (Sport_ID)

对于他们“将所有内容存储在varchar列中”,我想这将是一个更复杂的CHECK约束,使用UDF查询其他表。它会变得混乱和程序化。另外,如果你想阻止一行被sports移除,而member仍在被sports引用,那你就是要讨论members表上必须查询每一行的触发器在member_sports 2 `。

最后,让我们说,对于同一项运动多次记录同一项运动是没有意义的。对于CONSTRAINT UQ_Member_Sports UNIQUE (Member_ID,Sport_ID) ,即(如果它不是PK):

CHECK

对于他们“将所有内容存储在varchar列中”,这是另一个从varchar约束中调用的可怕程序UDF。

即使如果 member_sports变体表现得更好(不太可能,因为你需要将字符串分开并且T-SQL的字符串操作函数非常弱(参见上面的re:regex))某些“表现更好”的价值,他们如何建议数据有意义而不是废话?

编写可以应对废话的程序变体是一项更具挑战性的工作。

如果从上面不清楚 - 我是声明参照完整性(DRI)的粉丝。陈述你想要什么而不是关注机制是SQL吸引我的重要原因。您构建了正确的DRI,并且知道您的数据始终是正确的(或者,至少,正如您所期望的那样)

1 “应用程序将始终正确执行此操作”并不是一个好的答案。如果您设法构建一个应用程序和相关数据库,其中 nobody 曾编写一些直接SQL来修复某些内容,我想您将成为第一个。

但在大多数情况下,总会有多个应用程序,即使其他应用程序是仅由开发人员使用的直接SQL客户端,您已经无法相信应用程序将始终正确运行。应用程序中的错误比SQL数据库引擎的约束实现中的错误更有可能,这些约束的测试次数远远超过任何单个应用程序试图强制执行约束的次数。

2 更不用说更有可能的查询 - 找到与特定运动相关的所有成员。 sport_id上的第二个索引使这成为一个简单的查询 3 。没有索引可以帮助“它在这个字符串中的某个地方”解决方案,而且您正在查看没有索引机会的表扫描。

3 首先const obj = { a: 1 }; const obj2 = { ...obj }; 的任何索引都应该能够满足这样的查询。