8.5 SQL Server覆盖索引
SQL Server覆盖索引
简介
本文使用sales.customers表作为示例

下面语句在email列创建唯一约束:
| CREATE UNIQUE INDEX ix_cust_email | |
| ON sales.customers(email); |
查找电子邮件为“aide.franco@msn.com”的客户:
| SELECT | |
| customer_id, | |
| FROM | |
| sales.customers | |
| WHERE | |
| email = 'aide.franco@msn.com'; |
打开执行计划,您会发现查询优化器使用的是非聚集索引查找(Index Seek)操作,这样的查找性能来很高。

然而,请看下面语句:
| SELECT | |
| first_name, | |
| last_name, | |
| FROM | |
| sales.customers | |
| WHERE email = 'aide.franco@msn.com'; |

在这个执行计划中:
首先,查询优化器使用email列的非聚集索引ix_cust_email上的索引查找来查找email和customer_id。

其次,查询优化器使用sales.customers表的聚集索引的键查找。按客户id(customer_id)查找客户的名字(first_name)和姓氏(last_name)。

总之就是,对于在非聚集索引中找到的每一行,它使用嵌套循环与聚集索引中发现的行相匹配。
可以清晰的看到,键查找的开销约为查询的50%,这个开销很大。
为了帮助减少这种键查找开销,SQL Server可以通过包含非键列来增加非聚集索引包含的列。
通过在非聚集索引中包含非键列,可以创建覆盖更多查询的非聚集索引,这就叫做索引覆盖。
注意,当索引包含查询引用的所有列时,这样的查询通常称为覆盖查询。
首先,从sales.customers表中删除email列上的非聚集索引ix_cust_email:
| DROP INDEX ix_cust_email | |
| ON sales.customers; |
然后,在email列上创建一个新索引ix_cust_email_inc,并额外包括两列first_name和last_name:
| CREATE UNIQUE INDEX ix_cust_email_inc | |
| ON sales.customers(email) | |
| INCLUDE(first_name,last_name); |
现在,查询优化器将只使用非聚集索引来返回查询的请求数据:

包含列的索引可以大大提高查询性能,因为查询中的所有列都包含在索引中;查询优化器可以定位索引中的所有列值,而无需访问表或聚集索引,从而减少磁盘I/O操作。
键列存储在索引的所有级别中,而非键列仅存储在叶级别中。
注意:键列存储在索引的所有级别中,而非键列仅存储在叶级别中。
创建包含列的索引的语法
| CREATE [UNIQUE] INDEX index_name | |
| ON table_name(key_column_list) | |
| INCLUDE(included_column_list); |
浙公网安备 33010602011771号