-1

我有一个查询:

UPDATE TOP(100000) pv
SET    pv.intUrlId = urls.intUrlId
FROM   [schema1].[Urls] urls WITH(NOLOCK)
       INNER JOIN [schema2].[PageViews] pv WITH(NOLOCK)
         ON pv.urlId = urls.id
            AND pv.intUrlId IS NULL 

此查询中使用的每一列都是一个索引,urls.id 是一个主键。但是查询还是太慢了。为了提高性能,我重建了 pv_urlId_IDX 索引,将 pv.intUrlId 列添加为“包含列”。我的推理如下:查询需要搜索 pv_urlId_IDX 索引来执行 JOIN 和下一个 pv_intUrlId_IDX 以确定 NULL 记录。如果我将 pv.intUrlId 的值添加到 pv_urlId_IDX 索引,则会“就地”执行第二个条件的测试,并且不会执行搜索第二个索引。不幸的是,我没有注意到任何性能提升。

我还阅读了 SQL Server 文档,他们每次都在包含列的范围内提到非键列。所以我的问题是:在索引中包含键列是否有意义,如果我们可以从这种解决方案中受益。

4

3 回答 3

1

如果没有实际的执行计划和CREATE TABLE语句,这里有一些想法:

  • Urls (id) INCLUDE (intUrlId)不需要删除。这可能是该陈述的最佳索引(on Urls) 。UPDATE它对聚集索引的改进是大还是小取决于表的宽度,但肯定不会更糟,优化器会为此选择它。

  • 删除WITH (NOLOCK). 网络上有很多链接,StackOverflow 本身也有很多链接,这些链接解释了为什么它通常是不好的做法。

  • 考虑(并测试)在 上添加索引PageViews (intUrlId, urlId)或部分索引PageViews (urlId) WHERE intUrlId IS NULL。两者都将提高查找需要更新的行的效率。它们是一种双面选项,尽管随着语句的索引更新所需的时间也会增加(要更新一个索引。)

  • 最后 - 但并非最不重要 - 尝试将UPDATE语句拆分为更小的块。例如,您可以运行 100 条语句,TOP (1000)而不是您正在运行的 100K 大更新并测试效率。

要回答你的问题,不,索引PageViews (urlId) INCLUDES (intUrlId)不会很有用。因为它向表中添加了一个索引(UPDATE也必须更新),并且因为它比上述两个建议的索引中的任何一个都具有更少的选择性。

于 2013-09-10T11:26:38.200 回答
1

要记住的几个项目:

  • 你调查过execution plan吗?
  • 我看到您正在更新100000行,请注意,当它看到您在表中选择超过x%的行时,从到的optimizer变化很多次。Index SeekTable Scan
  • 一旦您将一列包含在索引中,由于您正在更新它(从到) ,您的UPDATE速度会变慢NULLurls.intUrlId
  • 正如@MartinSmith 所写,您的 WITH(NOLOCK) 无关紧要,您是否检查过您是否已被锁定?
于 2013-09-10T10:25:39.080 回答
0

每列上
的索引都是问题禁用索引

[schema2].[PageViews].[intUrlId]

执行更新然后重建该索引

更新使用该索引来检查空值。
我宁愿处理列扫描而不是维护该索引。
如果在多次更新后更新速度变慢,那么问题很可能是索引变得碎片化。

尝试更大的顶部,甚至可能没有顶部。

删除 (nolock) 并让优化器决定

disable index on [schema2].[PageViews].[intUrlId]

UPDATE top (100000) pv
   SET pv.intUrlId = urls.intUrlId  
  FROM [schema1].[Urls] urls WITH (NOLOCK)
 INNER JOIN [schema2].[PageViews] pv
    ON pv.urlId = urls.id
   AND pv.intUrlId IS NULL

rebuild index
于 2013-09-10T12:52:29.497 回答