我有一张表,如下所示。我们将其命名为Fools
。
愚人号 | 愚人价值 | 是否为主动值 |
---|---|---|
1 | 极其愚蠢 | 0 |
1 | 超级愚蠢 | 1 |
2 | 相当愚蠢 | 1 |
业务规则是,对于每个FoolID
,我们只能在一行上IsActiveFoolValue
设置1
。我需要某种键或约束来强制执行这一点。但是,据我所知,键和约束无法做到这一点。唯一的工具是唯一索引,例如
CREATE UNIQUE NONCLUSTERED INDEX OnlyOneActiveFoolValuePerFoolId
ON Fools(FoolID)
WHERE IsActiveFoolValue = 1
这算是反模式吗?索引不应该是约束。它们应该是性能工具。约束应该由键、约束和触发器来强制执行。如果它被认为是反模式,它会带来什么缺点,还有什么替代方案?
我假设使用 SQL Server 2019,因为唯一筛选索引的某些功能在非常旧的版本中并不存在,并且我想保留任何现代替代方案的选项。
它们不完全被视为反模式,但在某种程度上是一种非规范化。
根据非常严格的第六范式规则,您确实应该删除该
bit
列并创建一个单独的表。但过滤唯一索引本质上可以做同样的事情,而且不需要太多样板代码。这是强制表的一部分具有唯一性的一种常见方法。您不应该觉得这有问题,这是一种非常标准的处理方法,并且不会比拥有可空列更糟糕。
此外,我不同意“索引不应该是约束。它们应该是性能工具。”您不能仅仅为了提高性能而向表添加唯一约束,您需要知道数据是否符合要求。归根结底,唯一索引是一种约束,因为它会在重复时引发错误。
而且在很多情况下它们实际上比普通的唯一约束要好得多
INCLUDE
,因为它们可以有列,所以它们可以同时发挥两种功能。顺便说一句,您的具体示例可能应该使用临时表或某些类似功能来实现。
比愚人表更现实的用途是某种带有版本行的表样式,其中标记了当前行。当然,只能有一个当前行,并且需要对这些行进行快速的索引访问。
我猜测可能会以某种方式滥用索引,但使用唯一索引来强制唯一性几乎不算是滥用。
这个例子有点奇怪。你有一个 FoolID,我本来希望它是表的主键。把它变成一种过滤主键似乎不太合适。
使用筛选索引来确保行子集中的某些内容是唯一的,这是可以的。类似的做法是确保 Name 和 ParentID 的组合是唯一的,但只有 IsActive=1 时才有意义。这样,您可以软删除行,但允许重新创建具有相同名称的项目。
需要注意一些事项。以您的示例为例,筛选索引不能用于以下查询:
如果您想利用 FoolID 上的索引,则需要小心始终使用 IsActiveFoolValue=1。或者您可能需要在 FoolID 上有一个未经过滤的额外索引,这会产生额外的开销。
您可能可以考虑其他选择,但我认为使用唯一过滤索引本身并没有什么错误。