Week 8: Covering Indexes & Tipping Point
当我们需要根据非聚集索引的字段作为条件来检索数据, 但返回的字段又不包含在非聚集索引中. 这种情况, 需要走两遍索引(一遍非聚集,一遍聚集),有时候这样做并不是很有效率,我们可以用Covering Index(包含索引)来解决.
Covering Indexes
包含索引也是非聚集索引的一种, 唯一的不同是索引中包含了请求字段的值. 我们通过例子来了解:
下面的查询将会使用Bookmark lookup, 因为PostalCode 并不是非聚集索引IX_Address_StateProvinceID的一部分,
SELECT AddressID, PostalCode FROM Person.Address WHERE StateProvinceID = 42 GO
这个查询产生了18个逻辑读.
下面我们创建一个包含了PostalCode值的包含索引,
CREATE NONCLUSTERED INDEX idxAddress_StateProvinceID ON Person.Address (StateProvinceID) INCLUDE (PostalCode) GO
再重新执行查询, 此时就变成了Index Seek(NonClustered)操作,逻辑读降成了2个,非常大的性能提升.
Tipping Point
有些情况,SQL Server能判断使用Bookmark Lookup耗能过高而弃用, 改为整个表的Scan操作. 这个判断的依据我们称之为临界点(Tipping Point).
在你需要查询的页数占据1/4到1/3之间时,会触发临界点. 但是没有准确的数字,因为每页包含的记录数并不相同.
举个例子,我们有个表每条记录都是400bytes的大小,也就是每页能存储20条记录.然后在value列上建一个非聚集索引,下面的查询使用Bookmark Lookup返回了1061行
SELECT * FROM Customers WHERE Value < 1062 GO
而如果多返回一行,这个查询就过了临界点,改成Scan了这个表
SELECT * FROM Customers WHERE Value < 1063 GO
两个几乎一样的查询,却是不同的执行计划.有时候这会导致一些严重的问题,因为我们不再有稳定的计划.
Summary
我们学习了SQL Server中的不同类型的索引,这些索引都可以提高数据库的读性能,但副作用是会降低写性能.每当我们执行insert,update,delete操作时,都有可能导致索引的维护工作.
因此我们需要根据数据库的读与写的工作量来评估索引战略.