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

dad*_*dde 18 sql t-sql sql-server sql-server-performance database-indexes

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

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

包含的索引

CREATE NONCLUSTERED INDEX IX_Address_PostalCode  
ON Person.Address (PostalCode) 
INCLUDE (AddressLine1, AddressLine2, City, StateProvinceID); 
Run Code Online (Sandbox Code Playgroud)

'正常'指数

CREATE NONCLUSTERED INDEX IX_Address_PostalCode  
ON Person.Address (PostalCode, AddressLine1, AddressLine2, City, StateProvinceID);
Run Code Online (Sandbox Code Playgroud)

Dis*_*ned 17

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

注意不要将"索引数据页"与存储大多数实际数据列的"数据页"(聚簇索引的叶页)混淆.

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

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

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

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

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

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

  • 这是一个常见的索引调整"技巧",可以扩展索引的键,以包含索引/过滤器中不需要的列.(称为覆盖指数.)
  • 这些列通常在输出列中是必需的,或者作为参考列用于连接到其他表.
  • 这将避免臭名昭着的"书签查找",但缺点是使索引"更宽"而不是严格必要.
  • 实际上,索引中较早的列通常已经识别出唯一的行,这意味着如果不是"避免书签查找"的好处,额外包含的列将是完全冗余的.
  • INCLUDE 列基本上可以更有效地获得相同的好处.

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


Pரத*_*ீப் 6

在第一个索引中,Index pagePostalCode是键列,并且AddressLine1, AddressLine2, City, StateProvinceID是叶节点的一部分以避免key/RID查找

当我的表总是被过滤时,我会更喜欢第一个索引,PostalCode并且这些列中的任何一个AddressLine1, AddressLine2, City, StateProvinceID都将是select过滤的一部分而不是过滤

select AddressLine1, AddressLine2, City, StateProvinceID
from Person.Address 
Where PostalCode=  
Run Code Online (Sandbox Code Playgroud)

在第二个索引中Index page,将有五个关键列PostalCode, AddressLine1, AddressLine2, City, StateProvinceID

当我有可能过滤数据时,我会更喜欢第二个索引

Where PostalCode = And AddressLine1 = 
Run Code Online (Sandbox Code Playgroud)

要么

Where PostalCode = And AddressLine2 = 
Run Code Online (Sandbox Code Playgroud)

要么

Where PostalCode = And AddressLine1  = and AddressLine2 = 
Run Code Online (Sandbox Code Playgroud)

等等..

在任何情况下,索引中的第一列应该是过滤的一部分以利用该指数