想要在过滤索引中放置OR时有什么解决方法?


8

想要在过滤索引中放置OR时有什么解决方法?

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

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

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

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

Answers:


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);

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

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);

这将使用在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);

或者,对您自己的答案中使用的方法进行更改:

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;

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

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

1

不好,但是似乎可以正常工作:

create index FIDX_tblbOrders_sdtmOrdCreated_INCL 
on dbo.tblBOrder(sdtmOrdCreated)
INCLUDE (sintMarketID,
         strCurrencyCode,
         sintOrderStatusID
         )
WHERE ((sintMarketId=1)
AND ( sintOrderStatusId IN (0,1,2,3,4,5,6,7,8,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30)))

当我尝试以更好的方式进行操作时,它不喜欢它:

在此处输入图片说明


1
根据MSND文档:“过滤的索引是在一个表上定义的,仅支持简单的比较运算符。如果需要引用多个表或具有复杂逻辑的过滤器表达式,则应创建一个视图。” msdn.microsoft.com/en-us/library/cc280372.aspx
帕维尔Tajs
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.