包含键列的索引

时间:2013-09-10 09:52:20

标签: sql sql-server tsql

我有一个问题:

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是PRIMARY KEY。但查询仍然太慢。尝试提高性能我已经重建了pv_urlId_IDX索引,将pv.intUrlId列添加为“包含列”。我的推理如下:查询需要搜索pv_urlId_IDX索引来执行JOIN和下一个pv_intUrlId_IDX来确定NULL记录。如果我将pv.intUrlId的值添加到pv_urlId_IDX索引,则将“就地”执行第二条件的测试,并且将不执行搜索第二索引。不幸的是,我没有注意到任何性能提升。

我还阅读了SQL Server文档,并且每次都提到包含范围的非键列。所以我的问题是:索引中的关键列是否有意义,如果我们能够从这样的解决方案中获益,那么它是否正确。

3 个答案:

答案 0 :(得分:1)

要记住的事项很少:

  • 你看过execution plan了吗?
  • 我发现您要更新100000行,请注意,当optimizer Index Seek更改为Table Scan时,UPDATE会更改{ x%表中的行。
  • 一旦您的索引中包含一列,您的NULL会因为您的更新而变慢(从urls.intUrlId到{{1}})
  • 正如@MartinSmith所写,你的WITH(NOLOCK)无关紧要,你检查一下你是否被锁定了吗?

答案 1 :(得分:1)

如果没有实际执行计划和CREATE TABLE语句,请参阅以下内容:

  • 不需要删除Urls (id) INCLUDE (intUrlId)。它可能是此Urls语句的最佳索引(在UPDATE上)。它是否对聚集索引进行了大大小小的改进取决于表的宽度,但它肯定不会更糟,优化器会选择它。

  • 删除WITH (NOLOCK)。网上有很多链接,很多关于StackOverflow本身的链接解释了为什么它一般都是不好的做法。

  • 考虑(并测试)在PageViews (intUrlId, urlId)上添加索引或在PageViews (urlId) WHERE intUrlId IS NULL上添加部分索引。两者都将提高查找需要更新的行的效率。虽然索引更新语句所需的时间也会增加(还有一个要更新的索引),但它们有两种选择。 )

  • 和最后 - 但并非最不重要 - 尝试的是将UPDATE语句拆分为较小的块。您可以使用TOP (1000)运行100个语句,而不是运行的100K更新和测试效率。

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

答案 2 :(得分:0)

每列的索引都是问题

上禁用索引
[schema2].[PageViews].[intUrlId]

执行更新 然后重建该索引

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

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

删除(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