SQL 有条件的服务器索引

SQL Server index with condition

我有 table Range

Start (date), RangeTypeId (integer), ChannelId (integer), IsActive (bit)

我有这个索引:

CREATE UNIQUE NONCLUSTERED INDEX [IX_Range_Unique] 
ON [dbo].[Range] ([Start] ASC, [RangeTypeId] ASC, [ChannelId] ASC, [IsActive] ASC)

我希望我的索引仅在具有 IsActive = 1 的 2 行的情况下防止插入或更新。所以我想要索引或某种触发器,允许多个 Ranges 具有 IsActive = 0 和相同的开始日期、频道 ID 和类型,但只有一个具有 IsActive = 1 和相同的开始日期,频道 ID 和类型。

有效数据库示例 table 状态:

Start | RangeTypeId | ChannelId | IsActive
------------------------------------------
23:00        5           1          0  
23:00        5           1          0  
23:00        5           1          0  
23:00        5           1          1  

无效:

Start | RangeTypeId | ChannelId | IsActive
------------------------------------------
23:00        5           1          0  
23:00        5           1          0  
23:00        5           1          1  
23:00        5           1          1  

可能吗?

您可以像这样创建独一无二的 filtered index

CREATE UNIQUE NONCLUSTERED INDEX [uIXf_Range_Unique] ON [dbo].[Range]
(
    [Start] ASC,
    [RangeTypeId] ASC,
    [ChannelId] ASC,
    [IsActive] ASC
)
where IsActive = 1

rextester 演示:http://rextester.com/LBI81243


create table range ([Start] varchar(5), [RangeTypeId] int, [ChannelId] int, [IsActive] int) ; 
insert into range ([Start], [RangeTypeId], [ChannelId], [IsActive]) values
('23:00', 5, 1, 0),
('23:00', 5, 1, 0),
('23:00', 5, 1, 0),
('23:00', 5, 1, 1)
;
CREATE UNIQUE NONCLUSTERED INDEX [uIXf_Range_Unique] ON [dbo].[Range]
(
    [Start] ASC,
    [RangeTypeId] ASC,
    [ChannelId] ASC,
    [IsActive] ASC
)
where IsActive = 1
go
/* throws an error error due to duplicate key */
insert into range ([Start], [RangeTypeId], [ChannelId], [IsActive]) values
('23:00', 5, 1, 1)

恕我直言,UNIQUE FILTERED INDEX 有一大缺点。

索引的主要目的是加速select查询。 所以上面的索引可能在大多数 select 查询中都没有使用,在这种情况下我们经常更改索引 .

所以索引的主要目的是 defeated.In 在这种情况下我们删除索引并在其他 column/columns 上创建索引 column/columns。

Filtered index 的想法也不同于使用 here.Purpose 过滤索引是,如果在大量数据中,我们非常频繁地查询某个值,那么我们会使用该值在该列上创建过滤索引喜欢 above.Its 目的不是提供唯一性。

假设 DBA 不知道此计划并且 DBA 决定删除此索引,那么您可能会开始获取重复记录。

因此,在这种情况下检查重复项的最佳方法是通过代码进行检查。

if not exists (select id from mytable where [Start]=@Start and  [RangeTypeId]=@RangeTypeId
    and  [ChannelId]=@ChannelId and [IsActive]=1)
    BEGIN
    print 'insert'
    END

如果 insert/update 可以从多个地方发生,那么使用触发器是明智的。