Create Index语句的Include作用

本文介绍如何在SQLServer2005中利用非聚集索引的包含性非键列来提高查询性能,通过避免索引大小限制,合理设计索引结构,减少磁盘I/O操作。
在 SQL Server 2005 中,可以通过将非键列添加到非聚集索引的叶级别来扩展非聚集索引的功能。通过包含非键列,可以创建覆盖更多查询的非聚集索引。这是因为非键列具有下列优点:

它们可以是不允许作为索引键列的数据类型。 


在计算索引键列数或索引键大小时,数据库引擎 不考虑它们。


当查询中的所有列都作为键列或非键列包含在索引中时,带有包含性非键列的索引可以显著提高查询性能。这样可以实现性能提升,因为查询优化器可以在索引中找到所有列值;不访问表或聚集索引数据,从而减少磁盘 I/O 操作。

注意:  
当索引包含查询引用的所有列时,它通常称为“覆盖查询”。 
 


键列存储在索引的所有级别中,而非键列仅存储在叶级别中。有关索引级别的详细信息,请参阅表组织和索引组织。

使用包含性列以避免大小限制
可以将非键列包含在非聚集索引中,以避免超过当前索引大小的限制(最大键列数为 16,最大索引键大小为 900 字节)。数据库引擎 计算索引键列数或索引键大小时,不考虑非键列。 

例如,假设要为 AdventureWorks 示例数据库的 Document 表中的以下列建立索引:

  Title nvarchar(50) 

  Revision nchar(5) 

  FileName nvarchar(400) 

因为 nvarchar 数据类型要求每个字符 2 个字节,所以包含这三列的索引将超过 900 字节的大小限制,多了 10 个字节 (455 *2)。使用 CREATE INDEX 语句的 INCLUDE 子句,可以将索引键定义为 (Title, Revision),将FileName 定义为非键列。这样,索引键大小将为 110 个字节 (55 *2),并且索引仍将包含所需的所有列。下面的语句就创建了这样的索引。

 复制代码 
USE AdventureWorks;
GO
CREATE INDEX IX_Document_Title  
ON Production.Document (Title, Revision)  
INCLUDE (FileName);  
 

带有包含性列的索引准则
设计带有包含性列的非聚集索引时,请考虑下列准则: 

在 CREATE INDEX 语句的 INCLUDE 子句中定义非键列。


只能对表或索引视图的非聚集索引定义非键列。


除 text、ntext 和 image 之外,允许所有数据类型。


精确或不精确的确定性计算列都可以是包含性列。有关详细信息,请参阅为计算列创建索引。


与键列一样,只要允许将计算列数据类型作为非键索引列,从 image、ntext 和 text 数据类型派生的计算列就可以作为非键(包含性)列。 


不能同时在 INCLUDE 列表和键列列表中指定列名。


INCLUDE 列表中的列名不能重复。



列大小准则
必须至少定义一个键列。最大非键列数为 1023 列。也就是最大的表列数减 1。


索引键列(不包括非键)必须遵守现有索引大小的限制(最大键列数为 16,总索引键大小为 900 字节)。


所有非键列的总大小只受 INCLUDE 子句中所指定列的大小限制;例如,varchar(max) 列限制为 2 GB。



列修改准则
修改已定义为包含性列的表列时,要受下列限制: 

除非先删除索引,否则无法从表中删除非键列。


除进行下列更改外,不能对非键列进行其他更改: 


将列的为空性从 NOT NULL 改为 NULL。


增加 varchar、nvarchar 或 varbinary 列的长度。 

注意:  
这些列修改限制也适用于索引键列。 
 



设计建议
重新设计索引键大小较大的非聚集索引,以便只有用于搜索和查找的列为键列。将覆盖查询的所有其他列设置为包含性非键列。这样,将具有覆盖查询所需的所有列,但索引键本身较小,而且效率高。

例如,假设要设计覆盖下列查询的索引。

 复制代码 
USE AdventureWorks;
GO
SELECT AddressLine1, AddressLine2, City, StateProvinceID, PostalCode
FROM Person.Address
WHERE PostalCode BETWEEN N'98000' and N'99999';
 

若要覆盖查询,必须在索引中定义每列。尽管可以将所有列定义为键列,但键大小为 334 字节。因为实际上用作搜索条件的唯一列是 PostalCode列(长度为 30 字节),所以更好的索引设计应该将 PostalCode 定义为键列并包含作为非键列的所有其他列。 

下面的语句创建了一个覆盖查询的带有包含性列的索引。

 复制代码 
USE AdventureWorks;
GO
CREATE INDEX IX_Address_PostalCode  
ON Person.Address (PostalCode)  
INCLUDE (AddressLine1, AddressLine2, City, StateProvinceID);  
 

性能注意事项
避免添加不必要的列。添加过多的索引列(键列或非键列)会对性能产生下列影响: 

一页上能容纳的索引行将更少。这样会使 I/O 增加并降低缓存效率。


需要更多的磁盘空间来存储索引。特别是,将 varchar(max)、nvarchar(max)、varbinary(max) 或 xml数据类型添加为非键索引列会显著增加磁盘空间要求。这是因为列值被复制到了索引叶级别。因此,它们既驻留在索引中,也驻留在基表中。


索引维护可能会增加对基础表或索引视图执行修改、插入、更新或删除操作所需的时间。


您应该确定修改数据时在查询性能上的提升是否超过了对性能的影响,以及是否需要额外的磁盘空间要求。有关评估查询性能的详细信息,请参阅查询优化
<think>好的,我现在需要帮助用户解答关于如何在STUDENT表的SNAME字段上创建唯一索引的问题。首先,我得回忆一下用户之前的问题历史,看看有没有相关的上下文。之前用户询问过使用ALTER语句修改表结构,包括添加字段、删除字段和外键约束的操作,所以现在可能是在同一个数据库设计或维护的上下文中。 用户这次的请求是使用CREATE INDEX语句在SNAME字段上创建唯一索引。首先,我需要确认用户是否真的需要唯一索引,因为唯一索引和普通索引的作用不同。唯一索引不仅加速查询,还会强制该字段的值唯一,防止重复。这可能意味着SNAME字段在业务逻辑中应该是唯一的,比如学生的姓名不能重复,但现实中姓名可能重复,所以需要确认用户的需求是否合理。如果用户确实需要确保姓名唯一,那么唯一索引是正确的选择;否则可能需要建议普通索引。 接下来,我需要考虑不同数据库系统的语法差异。用户之前的问题中提到了MySQLSQL Server和Oracle,所以在回答时需要涵盖这些系统的不同写法。例如,MySQL使用CREATE UNIQUE INDEX,而Oracle和PostgreSQL也类似,但SQL Server可能需要确认是否有特殊的语法要求。 然后,我需要解释索引的作用和创建索引的影响。比如,唯一索引会提高查询速度,但插入和更新操作可能会变慢,因为需要检查唯一性。此外,创建索引会占用额外的存储空间,这也是需要考虑的因素。 用户可能没有明确说明的深层需求可能是数据完整性的保证。通过唯一索引,可以避免重复数据,确保每个学生姓名唯一。但需要提醒用户现实情况中可能存在同名的情况,是否允许,否则唯一索引会导致插入错误。如果业务上允许同名,那么唯一索引可能不合适,应该改用普通索引。 另外,用户可能需要知道如何验证索引是否创建成功。比如在MySQL中使用SHOW INDEX FROM STUDENT,或者在SQL Server中使用sp_helpindex。这部分内容应该在回答中给出,帮助用户确认操作结果。 还要注意权限问题,创建索引需要相应的权限,用户可能需要有ALTER表的权限。如果用户遇到权限错误,可能需要检查他们的数据库账户权限。 最后,总结操作步骤,给出示例代码,并提醒注意事项,比如备份数据、考虑业务需求等。确保用户能够安全地执行操作,避免数据丢失或业务逻辑错误。</think>以下是使用`CREATE INDEX`语句在`STUDENT`表的`SNAME`字段上创建唯一索引的分步说明: --- ### **1. 创建唯一索引的语法** ```sql CREATE UNIQUE INDEX 索引名称 ON STUDENT(SNAME); ``` #### 示例代码: ```sql CREATE UNIQUE INDEX idx_student_sname_unique ON STUDENT(SNAME); ``` --- ### **2. 关键说明** 1. **唯一索引的作用** - 确保`SNAME`字段的值**唯一**,禁止重复值插入 - 加速基于`SNAME`字段的查询速度(如`WHERE SNAME='张三'`) 2. **适用场景** - 当需要强制保证学生姓名的唯一性时(如学籍系统) 3. **注意事项** - 若表中已有重复的`SNAME`值,创建索引会**失败** - 索引会占用额外存储空间,且可能影响插入/更新速度 --- ### **3. 验证索引是否创建成功** #### MySQL示例: ```sql SHOW INDEX FROM STUDENT; ``` #### SQL Server示例: ```sql EXEC sp_helpindex 'STUDENT'; ``` #### Oracle示例: ```sql SELECT index_name, uniqueness FROM user_indexes WHERE table_name = 'STUDENT'; ``` --- ### **4. 不同数据库的差异** | 数据库 | 语法特性 | |------------|----------------------------------| | **Oracle** | 支持相同语法 | | **PostgreSQL** | 可附加`CONCURRENTLY`参数避免锁表 | | **SQL Server** | 支持`INCLUDE`添加包含列 | --- ### **5. 扩展建议** - 若需允许重名但加速查询,改用普通索引: ```sql CREATE INDEX idx_student_sname ON STUDENT(SNAME); ``` - 若需组合唯一性(如`SNAME`+`SID`),使用复合索引: ```sql CREATE UNIQUE INDEX idx_name_id_unique ON STUDENT(SNAME, SID); ``` --- **操作前务必:** 1. 检查现有数据是否有重复值(`SELECT SNAME, COUNT(*) FROM STUDENT GROUP BY SNAME HAVING COUNT(*) > 1`) 2. 评估索引对写入性能的影响 3. 生产环境建议在低峰期操作
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值