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,
email
FROM
sales.customers
WHERE
email = 'aide.franco@msn.com';
打开执行计划,您会发现查询优化器使用的是非聚集索引查找(Index Seek)操作,这样的查找性能来很高。
然而,请看下面语句:
SELECT
first_name,
last_name,
email
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);