【问题标题】:Is it possible to write a Filtered Index where the column value is NOT LIKE 'X'?是否可以在列值不是“X”的情况下编写过滤索引?
【发布时间】:2014-09-18 21:06:27
【问题描述】:

我正在尝试优化表查找,因为执行计划显示了相当大量的并行表扫描。该表名为Opportunity,我过滤的列是Name。具体来说,我希望所有没有“补充”的行作为Name 的一部分:

WHERE ([Name] NOT LIKE '%Supplement%');

我一直在寻找一种优化方法,并遇到了我需要的过滤索引,但他们似乎不喜欢 LIKE 关键字。有没有其他方法可以创建这样的过滤索引?

该表有大约 53k 行,直接查询服务器时需要 4 秒才能获取数据,但是当我将其作为链接服务器(这是我需要的)查询时需要 2 分钟。为了改善这个时间,我将查询从与链接服务器对话的脚本中移出,并在远程服务器上创建了一个视图。仍然需要很长时间。

这是我迄今为止尝试过的,但 SSMS 说它无效:

CREATE NONCLUSTERED INDEX [FX_NotSupplementOpportunities]
    ON      [Opportunity]([Name])
    WHERE   (([Name] NOT LIKE '%Supplement%')
            AND ([Name] NOT LIKE '%Suplement%')
            AND ([Name] NOT LIKE '%Supplament%')
            AND ([Name] NOT LIKE '%Suppliment%'));

提前感谢您的任何建议!

【问题讨论】:

  • 很遗憾,您不能在 SQL-Server 的筛选索引条件中使用 LIKE
  • 有其他推荐吗?

标签: sql-server sql-server-2012 query-optimization filtered-index


【解决方案1】:

您可以使用Indexes on Computed Columns 一个例子是:

CREATE TABLE [dbo].[MyTab](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Text] [varchar](max) NULL,
    [OK]  AS (case when NOT [text] like '%abc%' then (1) else (0) end) PERSISTED NOT NULL,
 CONSTRAINT [PK_MyTab] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
CREATE NONCLUSTERED INDEX [idx_OK] ON [dbo].[MyTab] 
(
    [OK] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

【讨论】:

  • 感谢您接受,但@ypercube 的答案似乎更好,您可能会做出决定。
【解决方案2】:

很遗憾,您可以在过滤索引的条件中添加的内容有很多限制。

我在 MSDN 中找不到任何具体内容,但 Brent Ozar 的这篇博文:What You Can (and Can’t) Do With Filtered Indexes 提到了一些限制:

您不能使用BETWEENNOT INCASE 表达式、OR

他们没有提到LIKE,但简单的测试(就像你所做的那样)证实你也不能。你甚至不能使用(NOT (a >= 7)),它可以重写为允许的(a < 7)

一种想法是在持久列上使用 case 表达式,然后在过滤索引中使用持久列 - 但这是过滤索引的另一个限制!

那么,你是做什么的?唯一想到的是创建一个持久列并在简单(未过滤)索引中使用它。比如:

ALTER TABLE  dbo.Opportunity
    ADD special_condition AS (CASE WHEN [Name] NOT LIKE '%Supplement%' 
                                  THEN 1 ELSE 0 END) 
        PERSISTED;

然后添加一个索引,使用列:

CREATE NONCLUSTERED INDEX FX_NotSupplementOpportunities
    ON dbo.Opportunity
      (special_condition, [Name]) ;

并在您的查询中使用(WHERE special_condition = 1)

【讨论】:

    【解决方案3】:

    我选择了@bummi 的答案,因为它最接近我的尝试,但不是我最终使用的。一点解释...

    因此,经过数小时试图弄清楚如何使查询查找速度更快后,我实际上是从一堆并行化的块中得到了它,直到两个索引查找。我对此非常欣喜若狂,但最后我不得不放弃它。问题是远程数据库实际上是我们 Salesforce 数据的备份。我必须在同步前后进行一些非常复杂的表和列更改,这些更改无法正常工作,并且每次同步都会被删除(每 10 分钟一次)。

    在进行所有这些操作时,我最终意识到我正在导入数据,然后在我的最后再次对其进行格式化。我决定改为更新远程服务器上的视图并尽可能多地格式化那里的数据,然后将其导入。所以,我花了几个小时重新编写两边的 SQL,我设法将大约 25 分钟的脚本缩短到了大约 3 分钟,这让我非常高兴和满足。

    最后,尽管远程服务器上的查询查找未优化,但它们仍然相当快,主要是因为在我接触的大多数表中平均不超过约 50k 行...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-26
      • 1970-01-01
      • 1970-01-01
      • 2012-06-27
      • 2011-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多