当您想在过滤索引中放置 OR 时,是否有解决方法?

Mar*_*lli 8 sql-server filtered-index sql-server-2014

当您想在过滤索引中放置 OR 时,是否有解决方法?

create index FIDX_tblbOrders_sdtmOrdCreated_INCL 
on dbo.tblBOrder(sdtmOrdCreated)
INCLUDE (sintMarketID,
         strCurrencyCode,
         sintOrderStatusID
         )
WHERE ((sintMarketId=1)
AND ( (sintOrderStatusId < 9) OR (sintOrderStatusId > 14)))
Run Code Online (Sandbox Code Playgroud)

我正在尝试创建上面的索引,因为我对 sintOrderStatusId IN (9-14) 的任何情况都不感兴趣

当然,我可以创建视图或索引视图,但我试图避免这种情况。

只是添加更多信息:sintOrderStatusId 是 smallint NOT NULL 并且可能的值范围从 1 到 30。要避免 9 到 14,因此过滤索引。

Han*_*non 12

不幸的是,似乎没有办法为索引创建否定过滤器,而不必求助于创建物化视图。如果它可以创建负过滤器,例如你喜欢的人,这将是非常困难的查询优化器“选择”索引的使用,极大地增加所需要的时间找到一个很好的计划。

根据该表的查询模式,您可以简单地创建两个索引;一个用于小于9,一个用于大于这些索引的任一14可以由查询优化器用于简单地选择WHERE条款如WHERE StatusID = 6

CREATE TABLE dbo.TestNegativeFilter
(
    TestNegativeFilter INT NOT NULL
        CONSTRAINT PK_TestNegativeFilter
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , StatusID INT NOT NULL
);
GO

CREATE INDEX IX_TestNagativeFilter_LessThan9
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID < 9);

CREATE INDEX IX_TestNagativeFilter_GreaterThan14
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID > 14);
Run Code Online (Sandbox Code Playgroud)

实现此目的的另一种方法可能是:

CREATE INDEX IX_TestNegativeFilter_9_to_14
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID IN (9, 10, 11, 12, 13, 14));

SELECT *
FROM dbo.TestNegativeFilter tnf
EXCEPT
SELECT *
FROM dbo.TestNegativeFilter tnf
WHERE tnf.StatusID IN (9, 10, 11, 12, 13, 14);
Run Code Online (Sandbox Code Playgroud)

这使用在 9 到 14 上过滤的索引来排除行。

在我的测试设备上,一个简单的覆盖索引返回的行是迄今为止最快的:

CREATE NONCLUSTERED INDEX IX_TestNegativeFilter_StatusID
ON dbo.TestNegativeFilter(StatusID)
INCLUDE (TestNegativeFilter);

SELECT *
FROM dbo.TestNegativeFilter tnf
WHERE tnf.StatusID NOT IN (9, 10, 11, 12, 13, 14);
Run Code Online (Sandbox Code Playgroud)

或者,使用您自己的答案中使用的方法的变体:

CREATE INDEX [IX dbo.TestNegativeFilter StatusID not 9-14]
ON dbo.TestNegativeFilter (StatusID)
WHERE StatusID <> 9
AND StatusID <> 10
AND StatusID <> 11
AND StatusID <> 12
AND StatusID <> 13
AND StatusID <> 14;
Run Code Online (Sandbox Code Playgroud)

尽管过滤器被写为连接词,但它支持以以下任何一种方式编写的查询(第一种方式效率更高):

  • StatusID NOT IN (9, 10, 11, 12, 13, 14)
  • StatusID < 9 OR StatusID > 14
  • StatusID NOT BETWEEN 9 AND 14