我有一个简单的编制索引视图。当我查询反对它,它是很缓慢的。第一,我告诉你的架构和索引。然后简单的查询。最后一个查询计划screnie.

更新:证明的解决方案在底部这一员额。

架构

这是什么它看起来像:-

CREATE view [dbo].[PostsCleanSubjectView] with SCHEMABINDING AS
    SELECT PostId, PostTypeId, 
        [dbo].[ToUriCleanText]([Subject]) AS CleanedSubject
    FROM [dbo].[Posts]

我udf ToUriCleanText 仅仅是取代了各种各样的字符用空符。例如。代替所有'#'的字符"。

然后我加入两个索引:-

索引

主要的关键指标(即。聚集指数)

CREATE UNIQUE CLUSTERED INDEX [PK_PostCleanSubjectView] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [PostId] 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

和一个非集群指数

CREATE NONCLUSTERED INDEX [IX_PostCleanSubjectView_PostTypeId_Subject] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [CleanedSubject] ASC,
    [PostTypeId] 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

现在,这个约有25行。没什么大。

当我这样做以下的查询,他们都需要大约4奇数秒。跆拳道?这应该是..基本上瞬间!

查询1

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town'

查询2(加入另一个款项)

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

我做错了什么?是UDF拧吗?我认为,因为我们指数会这一观点,它将成为现实。这样,它将没有计算这串列。

这里有一个screenie的查询计划,如果这有助于:- alt text

此外,通知的索引,它是使用?为什么使用这一指数?

该索引是...

CREATE NONCLUSTERED INDEX [IX_Posts_PostTypeId_Subject] ON [dbo].[Posts] 
(
    [PostTypeId] ASC,
    [Subject] 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

所以,是的,任何想法伙计?

更新1:加架构udf。

CREATE FUNCTION [dbo].[ToUriCleanText]
(
    @Subject NVARCHAR(300)
)
RETURNS NVARCHAR(350) WITH SCHEMABINDING
AS 
BEGIN
   <snip>
   // Nothing insteresting in here. 
   //Just lots of SET @foo = REPLACE(@foo, '$', ''), etc.
END

更新2:解决方案

是的,这是因为我不用指数上看,不得不手动确保我没有扩大。服务器是Sql服务器2008年的标准版本。完整的答案如下。这里是证据 WITH (NOEXPAND) alt text

谢谢你帮我解决这个问题:)

有帮助吗?

解决方案

什么版SQL服务器?我认为,只有企业和开发人员版将使用索引视自动的,而其他支持,它使用的查询提示。

SELECT a.PostId
FROM PostsCleanSubjectView a WITH (NOEXPAND)
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

查询提示(办SQL)在MSDN:

该索引的观点是不仅扩大,如果认为直接引用中的选择部分的查询并与(NOEXPAND)或(NOEXPAND、索引(index_value[,...n]))是指定的。

其他提示

我在执行计划中的查询代码中看到@符号。有一个字符串变量。

如果字符串变量的类型与索引中字符串列的类型不匹配,则SQL Server具有NASTY行为。 Sql Server将... 将整个列转换为该类型,执行快速查找,然后丢弃已转换的索引,以便它可以在下次查询时再次执行整个操作。


西蒙想出来了 - 但这里有更多有用的细节: http:// msdn.microsoft.com/en-us/library/ms187373.aspx

  

如果查询包含对索引视图和基表中都存在的列的引用,并且查询优化器确定使用索引视图提供执行查询的最佳方法,则查询优化器使用视图上的索引。此功能称为索引视图匹配,仅在SQL Server Enterprise和Developer版本中受支持。

     

但是,为了使优化器考虑使用索引视图进行匹配或使用NOEXPAND提示引用的索引视图,必须将以下SET选项设置为ON:

所以,这里发生的是索引视图匹配无法正常工作。确保您使用的是Sql Server的Enterprise或Developer版本(很可能)。然后根据文章检查您的SET选项。

我最近构建了一个包含数亿个调用详细记录的大型数据库,并且我在查询和视图中使用了一些函数,并将其转换为持久计算列。这样做得更好,因为我可以对计算列进行索引。

我没有使用SQL Enterprise,所以我没有机会使用索引视图。索引视图是否应该能够索引UDF的确定性结果?

我怀疑它必须在每行调用该函数才能在where子句中进行比较。我将公开主题,直接运行查询检查,看看时间是如何运作的。每当我使用函数修改值然后在where子句中使用它时,我一般都会看到很多缓慢...

使用索引视图可以获得哪些好处?是否无法正确索引表格本身?如果没有充分的理由,您就会增加复杂性并要求优化器以更低的灵活性处理更多的数据库对象。

您是否使用标准索引评估了相同的查询逻辑?

混合使用UDF逻辑会使事情更加混乱。

如果您只想保留UDF的返回值,请考虑持久计算列而不是索引视图。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top