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上的索引查找来查找emailcustomer_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_namelast_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);
posted @ 2023-01-30 10:27  平元兄  阅读(176)  评论(0编辑  收藏  举报