Week 7: Non-Clustered Indexes
上周谈论的是聚集索引,当我们在一个表上定义一个聚集索引,就等于使用索引列来物理排序表. 除此之外,我们还可以在表上创建多个(最高999)非聚集索引.
我们用字典来比喻一下, 字典是按照拼音字母物理排序的(聚集索引), 当我们不知道某个字的读音时怎么查找呢? 利用字的笔画(非聚集索引), 首先在笔画表里根据笔画数找到要找的字的读音, 如果还需要知道更多说明,则根据该字记录的页数来对应具体的解释页.
SQL Server的非聚集索引也是这样工作的, 查询计划先在页级别的非聚集索引上查找,若要返回的字段不包含在非聚集索引中, 则还需要根据非聚集索引记录的lookup value,再去在聚集索引或heap上找.
这就是Bookmark Lookup
下面的图展示了一个典型的Bookmark Lookup执行计划.
![](https://images2015.cnblogs.com/blog/637437/201601/637437-20160104114943528-2144352282.png)
SQL Server先在非聚集索引上做了一个Seek操作, 以找到符合条件的行, 另外,又在聚集索引上通过 Key Lookup 操作返回其它select的列. 看起来这个功能很不错, 但实际上Bookmark Lookup非常非常危险.
它们会引起死锁, 并且性能会受到过期的统计信息的影响,
在非聚集索引的页级别, 存储了Lookup value,这是一个指向索引表或堆表中物理存储记录所在位置的指针.
如果是heap表,这个指针叫做 Row-Identifier,是一个8byte的值,其中4byte记录的页ID,2byte记录了文件ID,2byte记录了块ID.这些信息组合起来就是记录所在的物理位置.
如果是聚集表,这个指针就是聚集索引值. 所以我们在挑选索引键值的时候,要注意,如果某个键值也是其它非聚集索引的一部分,这将产生巨大的依赖关系,同时也产生冗余数据.
所以我们在选择索引键的时候,有3个最优的原则
- Unique
- Narrow
- Static
唯一性就不需要解释了, 窄字段的意义在于让你的索引更有效率. 而高度的静态化可以避免产生索引碎片等问题.