包含列的索引,区别是什么?

时间:2017-01-22 13:22:30

标签: sql sql-server tsql database-indexes sql-server-performance

我从来没有真正理解这两个索引之间的区别,有人可以解释一下有什么区别(性能方面,db中的索引结构如何,存储方式等)?

我理解这个问题很广泛,请耐心等待。我真的不知道如何限制它。也许如果你们开始解释你的诀窍,我会在正确的方向上得到指示,这使我能够使问题更加狭窄?

包含的索引

CREATE NONCLUSTERED INDEX IX_Address_PostalCode  
ON Person.Address (PostalCode) 
INCLUDE (AddressLine1, AddressLine2, City, StateProvinceID); 

'正常'索引

CREATE NONCLUSTERED INDEX IX_Address_PostalCode  
ON Person.Address (PostalCode, AddressLine1, AddressLine2, City, StateProvinceID);

3 个答案:

答案 0 :(得分:16)

索引的内部存储使用B树结构,由"索引页"组成。 (根页面和所有中间页面)和"索引数据页面" (仅限叶页。)

  

注意不要混淆"索引数据页"使用"数据页" (聚集索引的叶页),它存储了大部分实际数据列。

  • 索引页只存储索引列。
  • 通过在INCLUDE部分放置一些列,每个索引键的数据存储在每个页面上。
  • 意味着需要更少的页面来保存索引键。 (使这些经常使用的页面更容易在内存中缓存更长时间。
  • 树中的级别可能更少。 (在这种情况下,性能优势可能会大得多,因为每个树级别遍历都是另一个磁盘访问。

使用索引时,索引键用于将索引页面导航到正确的索引数据页。

  • 如果索引具有INCLUDE列,则在查询需要时,该数据立即可用。
  • 如果查询要求索引键或INCLUDE列中不可用的列,则需要额外的"书签查找"是聚簇索引中的正确行所必需的(如果没有定义聚簇索引,则为堆)。

有些事情要注意,希望能解决你的一些困惑:

  • 如果您的查询中的索引和过滤器的键不足选择,那么将忽略该索引(无论您的INCLUDE列中的内容是什么)。
  • 您创建的每个索引都有INSERT和UPDATE语句的开销;更重要的是"更大"索引。 (更大也适用于INCLUDE列。)
  • 因此,虽然理论上可以创建多个大型索引,其中包含列以匹配访问路径的所有排列:这将非常适得其反。

值得注意的是,在添加INCLUDE列作为功能之前:

  • 这是一个常见的索引调整技巧'扩展索引的键以包括索引/过滤器中不需要的列。 (称为覆盖指数。)
  • 这些列通常在输出列中需要,或者作为连接到其他表的参考列。
  • 这样可以避免臭名昭着的书签查找"但是有一个缺点,就是让索引“更宽”'绝对必要。
  • 事实上,索引中较早的列已经识别出 唯一行 ,这意味着如果不是"那么额外包含的列将是完全冗余的。避免书签查找"益处。
  • INCLUDE列基本上可以更有效地提供相同的效益。
  

NB 需要指出一些非常重要的事情。如果你总是把你的查询写成INCLUDE的懒惰习惯,你通常会从索引中的SELECT * ...列中获得零利益。通过返回 所有列 ,您基本上确保在任何情况下都需要书签查找。

答案 1 :(得分:6)

在第一个索引中,仅在LIBRARIES=-lDekaIndex page是关键列,PostalCode是叶节点的一部分,以避免AddressLine1, AddressLine2, City, StateProvinceID查找

我会更喜欢第一个索引,我的表格将始终在key/RID上过滤,而这些列PostalCode中的任何一个都将成为AddressLine1, AddressLine2, City, StateProvinceID的一部分,而不是过滤

select

在第二个索引中,在select AddressLine1, AddressLine2, City, StateProvinceID from Person.Address Where PostalCode= 中会有五个关键列Index page

当我有可能过滤像

这样的数据时,我会更喜欢第二个索引
PostalCode, AddressLine1, AddressLine2, City, StateProvinceID

Where PostalCode = And AddressLine1 = 

Where PostalCode = And AddressLine2 = 

依旧......

无论如何,索引中的第一列应该是过滤的一部分,以利用索引

答案 2 :(得分:2)

在第一个示例中,只有索引列:PostalCode存储在索引树中,其他所有列都存储在索引的叶级中。这使得索引的大小更小,如果您不使用where,Join,group by对其他列而只对照PostalCode,则该索引非常有用。

在第二个索引中,所有列的所有数据都存储在索引树中,这使得索引更大,但如果您要使用WHERE / JOIN / GROUP BY / ORDER中的任何列,则非常有用通过陈述。

包含列可以在选择列表中指定数据时更快地检索数据。

例如,如果您正在运行:

SELECT PostalCode, AddressLine1, AddressLine2, City, StateProvinceID 
FROM Person.Address 
Where PostalCode= 'A1234'

这将受益于在PostalCode上创建索引并包括所有其他列

另一方面,如果您正在运行:

SELECT PostalCode, AddressLine1, AddressLine2, City, StateProvinceID 
FROM Person.Address 
Where PostalCode= 'A1234' or City = 'London' or StateProvinceID = 1 or AddressLine1 = 'street A' or AddressLine2 = 'StreetB'

这将从索引中的所有列

中获益更多

查看下面的链接,这些可能会对您的查询提供更多帮助

  

包含列的索引:https://msdn.microsoft.com/en-us/library/ms190806(v=sql.105).aspx

     

表格和索引组织:https://msdn.microsoft.com/en-us/library/ms189051(v=sql.105).aspx