开文以前首先要讲讲几个概念html
【覆盖查询】数据库
当索引包含查询引用的全部列时,它一般称为“覆盖查询”。缓存
【索引覆盖】网络
若是返回的数据列就包含于索引的键值中,或者包含于索引的键值+汇集索引的键值中,那么就不会发生Bookup Lookup,由于找到索引项,就已经找到所需的数据了,没有必要再到数据行去找了。这种状况,叫作索引覆盖;工具
【复合索引】性能
和复合索引相对的就是单一索引了,就是索引只包含一个字段,因此复合索引就是包含两个或者多个字段的索引;学习
【非键列】测试
键列就是在索引中所包含的列,固然非键列就是该索引以外的列了;优化
下面就开始今天的主题设计
【摘要1】
在 SQL Server 2005 中,能够经过将非键列添加到非汇集索引的叶级别来扩展非汇集索引的功能。经过包含非键列,能够建立覆盖更多查询的非汇集索引。这是由于非键列具备下列优势:
* 它们能够是不容许做为索引键列的数据类型。
* 在计算索引键列数或索引键大小时,数据库引擎不考虑它们。
当查询中的全部列都做为键列或非键列包含在索引中时,带有包含性非键列的索引能够显著提升查询性能。这样能够实现性能提高,由于查询优化器能够在索引中找到全部列值;不访问表或汇集索引数据,从而减小磁盘 I/O 操做。
说明:第一:只能是针对非汇集索引;第二:比起复合索引是有性能上的提高的,由于索引的大小变小了;
【摘要2】
键列存储在索引的全部级别中,而非键列仅存储在叶级别中。
说明:这就表现为包含与不包含的关系了。有关索引级别的详细信息,请参阅表组织和索引组织。
【摘要3】
使用包含性列以免大小限制
能够将非键列包含在非汇集索引中,以免超过当前索引大小的限制(最大键列数为 16,最大索引键大小为 900 字节)。数据库引擎计算索引键列数或索引键大小时,不考虑非键列。
例如,假设要为 AdventureWorks 示例数据库的 Document 表中的如下列创建索引:
Title nvarchar(50)
Revision nchar(5)
FileName nvarchar(400)
由于 nchar 和 nvarchar 数据类型的每一个字符须要 2 个字节,因此包含这三列的索引将超出 900 字节的大小限制 10 个字节 (455 * 2)。使用 CREATE INDEX 语句的 INCLUDE 子句,能够将索引键定义为 (Title, Revision),将 FileName 定义为非键列。这样,索引键大小将为 110 个字节 (55 * 2),而且索引仍将包含所需的全部列。下面的语句就建立了这样的索引。
说明:当你把一个nvarchar(500)的字段设置为主键的时候,你就能够看到不能超出900字节的提示了。通常来讲咱们是不太会作这些操做的,因此那个错误提示也是不常见的,也许你可能还见过。
一个数据页的大小才8k,因此咱们合理的设置每一个字段的大小,不要浪费太多的空间,这样对查询也是有好处的,这个include就比较好的的解决了索引和空间的问题,虽然那些include的数据也会占用空间。
虽然能够设置include,可是也尽可能不要使用太多的字段做为索引包含的非键列。
【摘要4】
带有包含性列的索引准则
设计带有包含性列的非汇集索引时,请考虑下列准则:
* 在 CREATE INDEX 语句的 INCLUDE 子句中定义非键列。
* 只能对表或索引视图的非汇集索引定义非键列。
* 除 text、ntext 和 image 以外,容许全部数据类型。
* 精确或不精确的肯定性计算列均可以是包含性列。有关详细信息,请参阅为计算列建立索引。
* 与键列同样,只要容许将计算列数据类型做为非键索引列,从 image、ntext 和 text 数据类型派生的计算列就能够做为非键(包含性)列。
* 不能同时在 INCLUDE 列表和键列列表中指定列名。
* INCLUDE 列表中的列名不能重复。
说明:include不能使用在汇集索引中。后面的两点,这个在实际中很难想象会有这样的需求要把重复列放到一个索引中。若是有朋友遇到过这样的需求能够告知一些,不胜感激。那若是有是否能够经过不一样的列名(其实保存是一样的值)来解决这个问题呢??
【摘要5】
列大小准则
* 必须至少定义一个键列。最大非键列数为 1023 列。也就是最大的表列数减 1。
* 索引键列(不包括非键)必须遵照现有索引大小的限制(最大键列数为 16,总索引键大小为 900 字节)。
* 全部非键列的总大小只受 INCLUDE 子句中所指定列的大小限制;例如,varchar(max) 列限制为 2 GB。
说明:varchar(max)这样的定义是在2005以后才有的,因此这些数值也是对2005后的版本才生效的。
最大的表列数为:1024
最大非键列数为:1023
【摘要6】
修改已定义为包含性列的表列时,要受下列限制:
* 除非先删除索引,不然没法从表中删除非键列。
* 除进行下列更改外,不能对非键列进行其余更改:
o 将列的为空性从 NOT NULL 改成 NULL。
o 增长 varchar、nvarchar 或 varbinary 列的长度。
* 这些列修改限制也适用于索引键列。
说明:这些细小的东西一直没有注意过。因此要记录下来,用来“防身”,呵呵。
【摘要7】
设计建议
从新设计索引键大小较大的非汇集索引,以便只有用于搜索和查找的列为键列。将覆盖查询的全部其余列设置为包含性非键列。这样,将具备覆盖查询所需的全部列,但索引键自己较小,并且效率高。
说明:也就是说把经常使用的where后面的条件查询的字段做为索引的键列,而须要返回的字段就做为索引包含的非键列。
若是where的是两个或两个以上的谓词的话,这个索引就能够建立为复合索引了。之前天真的认为要返回的字段只能经过在复合索引中入这些字段,无论它是否会用来作谓词。看到这篇文章,才有了豁然开朗的感受。
【摘要8】
USE AdventureWorks;
GO
CREATE INDEX IX_Address_PostalCode
ON Person.Address (PostalCode)
INCLUDE (AddressLine1, AddressLine2, City, StateProvinceID);
说明:这个是使用include的语法,在表的设计中的索引设计中是没有办法选择的;
【摘要9】
性能注意事项
避免添加没必要要的列。添加过多的索引列(键列或非键列)会对性能产生下列影响:
* 一页上能容纳的索引行将更少。这样会使 I/O 增长并下降缓存效率。
* 须要更多的磁盘空间来存储索引。特别是,将 varchar(max)、nvarchar(max)、varbinary(max) 或 xml 数据类型添加为非键索引列会显著增长磁盘空间要求。这是由于列值被复制到了索引叶级别。所以,它们既驻留在索引中,也驻留在基表中。
* 索引维护可能会增长对基础表或索引视图执行修改、插入、更新或删除操做所需的时间。
您应该肯定修改数据时在查询性能上的提高是否超过了对性能的影响,以及是否须要额外的磁盘空间要求。有关评估查询性能的详细信息,请参阅查询优化。
说明:“这是由于列值被复制到了索引叶级别”这句很好的说明了物理上的存储结构和原理。
【图片解析】

上图也说明了为何不能在汇集索引中创建具备包含性列的索引,由于非汇集索引的叶层是由索引页而不是由数据页组成,这就得说到汇集和非汇集索引的的物理存储了,汇集索引的顺序排序和存储就是基表的顺序和存储结构。
【一个例子】
SELECT UserName,Password,RealName,Mobile,Age FROM bw_Users WHERE UserName = XXX AND Age = XX
说明:
- 这是一个咱们很常见的查询语句,咱们如何提升查询效率呢?
- 首先咱们来看看谓词,这条语句是经过UserName = XXX AND Age = XX做为条件的,那么咱们就应该创建一个组合索引,也称为复合索引,注意索引中的键列的位置,先UserName后Age;
- 其实上面那个是一个非汇集索引,那咱们就能够把Password,RealName,Mobile这三列做为索引包含列;
- 因此,最终就是创建一个以UserName 和 Age作为键列、Password,RealName,Mobile做为非键列的非汇集索引;
- 一般来讲咱们系统的用户表并非很大,因此这样的优化起不了很明显的效果,若是有兴趣的可使用大表进行性能测试;
【其它】
- 有一点我很奇怪,那就是为何在修改表的时候,为何【包含的列】是不可用的?只能经过命令来编写该类索引?
- 另一点我想说,微软的MSDN的确是最好的学习工具,在网络上搜索出来的东西不少都是重复的,并且说的不全,不过能讲的比较简单、通俗而已。因此有空仍是多看看MSDN吧。这句话是对本身说的。呵呵。
http://www.cnblogs.com/gaizai/archive/2010/01/11/1644358.html