包含列解析
所谓的包含列就是包含在非聚集索引中,并且不是索引列中的列。或者说的更通俗一点就是:把一些底层数据表的数据列包含在非聚集索引的索引页中,而这些数据列又不是索引列,那么这些列就是包含列。同时,这些包含列并不会对索引中的条目有影响。
好吧,为了使得问题稍微清楚一点,我用个简单的图示说明一下:

我们可以用下面的语句在创建索引的时候加入包含列,代码如下:

双击代码全选
1
2
3
CREATE NONCLUSTERED INDEX FK_ProductID_ ModifiedDate
ON Sales.SalesOrderDetail (ProductID, ModifiedDate)
INCLUDE (OrderQty, UnitPrice, LineTotal)
 

在上述的代码中,ProductID和ModifiedDate包含在索引键中,而OrderQty, UnitPrice, LineTotal作为包含列。
下面,我们就稍微深入到页级别来看看建立索引前后的状态。首先,我们看看,当建立非聚集索引,但是,索引中没有包含列的时候,索引中的索引页的详细如下:

在上图中可以看到,上面两个索引页是整个索引结构中的一部分,此时就包含了2个字段,而且这两个字段都是索引键,另外一个Bookmark是指向底层数据表中数据行的一个指针。
下面,我们再来看看,我们建立了有包含列的非聚集索引之后,索引页的情况,如下图:

很明显,原本的2个索引页被拆分成为了3个,因为一部分底层数据行的数据的数据包含在了索引页中。从这里就可以知道一点:加入包含列到非聚集索引中,增大了索引结构中页的个数,进而在使用的时候会占用更多的磁盘空间和内存空间。

其实把一些列作为包含列放在索引结构中就是一种用“空间换时间”的策略。
这个时候,大家可能就会问了:“何必把列放在包含列中这么麻烦,为什么不直接放在索引中?”。
其实把那三个列放在包含列而不是索引列中有以下几个好处:
1. 可以使得索引键变化引起的波动更小。举个例子,如果索引列中的ProductID或者ModifiedDate发生变化,那么索引结构就会要调整,重新定 位到底层的数据行。但是,如果UnitPrice的值发生了变化,整个索引的结构不会发生变化,只是在包含列中的UnitPrice的值进行更新而已。
2.索引中的数据列越少,数据分布的统计维护的成本就越小。
是否把一些作为索引列还是包含了其实也和数据库的类型和用途有很大的关系。例如在OLTP的数据库中,有很多的数据的增删改写的操作,那么建议索引中的列不要太多。如果是Warehouse类型的数据,那么就以大量数据的读取为主,那么可以考虑把很一些列包含在索引列中。
包含列实例演示一
下面通过是三个不同的小例子作为比较演示,并且以AdventureWorks中的SalesOrderDetail示例数据表:
1.演示没有非聚集索引的例子。
2.演示使用非聚集索引,但是没有包含列的例子
3.演示有非聚集索引和包含列的例子
在讲述的过程中,我们会结合实际的执行详情说明问题。
示例一:没有非聚集索引
执行语句如下:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
SET STATISTICS IO ON
    
SELECT ProductID ,
ModifiedDate ,
SUM(OrderQty) AS 'No of Items' ,
AVG(UnitPrice) 'Avg Price' ,
SUM(LineTotal) 'Total Value'
FROM Sales.SalesOrderDetail
WHERE ProductID = 888
GROUP BY ProductID ,
ModifiedDate ;
    
SET STATISTICS IO OFF
 
数据结果如下:

示例二:使用非聚集索引,但是没有包含列
首先运行下面的语句,建立索引:

双击代码全选
1
2
3
4
5
6
7
8
IF EXISTS ( SELECT FROM sys.indexes 
WHERE name 'FK_ProductID_ModifiedDate'
AND OBJECT_ID = OBJECT_ID('Sales.SalesOrderDetail') ) 
DROP INDEX Sales.SalesOrderDetail.FK_ProductID_ModifiedDate
    
    
CREATE NONCLUSTERED INDEX
FK_ProductID_ModifiedDateON Sales.SalesOrderDetail (ProductID, ModifiedDate)
 

然后再次运行示例中的查询。
示例三:有非聚集索引和包含列
首先执行下面的代码:

双击代码全选
1
2
3
4
5
6
7
IF EXISTS ( SELECT FROM sys.indexes 
WHERE name 'FK_ProductID_ModifiedDate'
AND OBJECT_ID = OBJECT_ID('Sales.SalesOrderDetail') ) 
DROP INDEX Sales.SalesOrderDetail.FK_ProductID_ModifiedDate
    
CREATE NONCLUSTERED INDEX FK_ProductID_ModifiedDateON Sales.SalesOrderDetail 
(ProductID, ModifiedDate) INCLUDE (OrderQty, UnitPrice, LineTotal) ;
 

然后再次运行之前的查询。
好了,三个例子完成之后,我们就来比较一下结果,如下:

示例 1:No Nonclustered Index Table 'SalesOrderDetail'. Scan count 1, logical reads 1238.Non read activity:  8%.
示例2:Index – No Included Columns   Table 'SalesOrderDetail'. Scan count 1, logical reads 131.Non read activity:  0%.
示例3:With Included Columns Table 'SalesOrderDetail'. Scan count 1, logical reads 3.Non read activity:  1%.

总结如下:
1.示例1中对整个表进行扫描,每一个行都要进行扫描,所以进行大量的IO活动。
2.例2首先使用非聚集索引找到ProductID的数据,然后通过书签查找找到查询中请求的其他的数据列。
3.示例3,只要在非聚集索引中查找需要的数据就行了,因为查询中所有列的数据都在里面了,不用查找底层的数据表,所以查询只是查找了索引结构,消耗的IO最少。
下面,我们就来看看第二个示例。
包含列示例演示二
第二个查询和第一个查询类似,只是将Where条件语句改为了按照ModifiedDate里过滤。语句如下:

双击代码全选
1
2
3
4
5
6
7
8
9
SELECT ModifiedDate ,
ProductID ,
SUM(OrderQty) 'No of Items' ,
AVG(UnitPrice) 'Avg Price' ,
SUM(LineTotal) 'Total Value'
FROM Sales.SalesOrderDetail
WHERE ModifiedDate = '2003-10-01'
GROUP BY ModifiedDate ,
ProductID ;
 
查询的结果如下显示:

在查询执行的过程中,通过Where条件,选择出了1496条数据,最后通过Group语句,使得最后显示的结果只有164行数据。
在三种不同的情况下,运行上面的查询,结果比较如下:

示例 1:No Nonclustered Index Table 'SalesOrderDetail'. Scan count 1, logical reads 1238.Non read activity:  10%.
示例2:With Index – No Included Columns Table 'SalesOrderDetail'. Scan count 1, logical reads 1238.Non read activity:  10%.
示例3:With Included Columns Table 'SalesOrderDetail'. Scan count 1, logical reads 761.Non read activity:  8%.

我 们可以知道,第一种情况和第二种情况下面的执行计划是一样的,都对整表进行扫描。而在第三种情况中,因为此时的ModifiedDate已经包含在了索引 的包含列中,此时就没有对整表进行扫描,而是对非聚集索引结构进行扫描。所以,可以知道:如何把一些列作为包含列放在索引中,那么就可以在一定的程度上面 提示效率,可以把原本需要整表扫描的操作,改为非聚集索引扫描,这样的成本更小。

SQL Server索引进阶第五篇:索引包含列 .的更多相关文章

  1. SQL Server索引进阶:第五级,包含列

    原文地址: Stairway to SQL Server Indexes: Level 5, Included Columns 本文是SQL Server索引进阶系列(Stairway to SQL ...

  2. SQL Server调优系列基础篇 - 索引运算总结

    前言 上几篇文章我们介绍了如何查看查询计划.常用运算符的介绍.并行运算的方式,有兴趣的可以点击查看. 本篇将分析在SQL Server中,如何利用先有索引项进行查询性能优化,通过了解这些索引项的应用方 ...

  3. SQL Server 调优系列基础篇 - 索引运算总结

    前言 上几篇文章我们介绍了如何查看查询计划.常用运算符的介绍.并行运算的方式,有兴趣的可以点击查看. 本篇将分析在SQL Server中,如何利用先有索引项进行查询性能优化,通过了解这些索引项的应用方 ...

  4. 【译】SQL Server索引进阶第八篇:唯一索引

    原文:[译]SQL Server索引进阶第八篇:唯一索引     索引设计是数据库设计中比较重要的一个环节,对数据库的性能其中至关重要的作用,但是索引的设计却又不是那么容易的事情,性能也不是那么轻易就 ...

  5. SQL Server索引设计 <第五篇>

    SQL Server索引的设计主要考虑因素如下: 检查WHERE条件和连接条件列: 使用窄索引: 检查列的选择性: 检查列的数据类型: 考虑列顺序: 考虑索引类型(聚集索引OR非聚集索引): 一.检查 ...

  6. SQL Server调优系列基础篇(索引运算总结)

    前言 上几篇文章我们介绍了如何查看查询计划.常用运算符的介绍.并行运算的方式,有兴趣的可以点击查看. 本篇将分析在SQL Server中,如何利用先有索引项进行查询性能优化,通过了解这些索引项的应用方 ...

  7. SQL Server 2005 中的分区表和索引

    SQL Server 2005 中的分区表和索引 SQL Server 2005          69(共 83)对本文的评价是有帮助 - 评价此主题   发布日期 : 3/24/2005 | 更新 ...

  8. SQL Server 2014新特性探秘(3)-可更新列存储聚集索引

    简介      列存储索引其实在在SQL Server 2012中就已经存在,但SQL Server 2012中只允许建立非聚集列索引,这意味着列索引是在原有的行存储索引之上的引用了底层的数据,因此会 ...

  9. SQL Server 性能调优2 之索引(Index)的建立

    前言 索引是关系数据库中最重要的对象之中的一个,他能显著降低磁盘I/O及逻辑读取的消耗,并以此来提升 SELECT 语句的查找性能.但它是一把双刃剑.使用不当反而会影响性能:他须要额外的空间来存放这些 ...

随机推荐

  1. BZOJ 3339 & 莫队+"所谓的暴力"

    题意: 给一段数字序列,求一段区间内未出现的最小自然数. SOL: 框架显然用莫队.因为它兹瓷离线. 然而在统计上我打了线段树...用&维护的结点...400w的线段树...然后二分查找... ...

  2. Codeforces Round #251 (Div. 2) C. Devu and Partitioning of the Array

    注意p的边界情况,p为0,或者 p为k 奇数+偶数 = 奇数 奇数+奇数 = 偶数 #include <iostream> #include <vector> #include ...

  3. Codeforces Round #228 (Div. 2) A. Fox and Number Game

    #include <iostream> #include <algorithm> #include <vector> #include <numeric> ...

  4. Code[VS]1690 开关灯 题解

    Code[VS]1690 开关灯 题解     时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description:     YYX家门前 ...

  5. Selenium_Selenium WebDriver 中鼠标和键盘事件分析及扩展

    在使用 Selenium WebDriver 做自动化测试的时候,会经常模拟鼠标和键盘的一些行为.比如使用鼠标单击.双击.右击.拖拽等动作:或者键盘输入.快捷键使用.组合键使用等模拟键盘的操作.在 W ...

  6. php随笔(一)

    之前的开发一直用的都是Thinkphp框架,对原生的php很不了解,近日打算把以前的项目拿一个出来用原生php再重写一次,顺便再把TP框架拆开好好分析分析. 之前的android开发虽说对面向对象的思 ...

  7. #1045 - Access denied for user 'root'@'localhost' (using password: NO)

    解决办法 打开 phpmyadmin里的config.inc.php文件 $cfg['Servers'][$i][ 'host'] = 'localhost';$cfg['Servers'][$i][ ...

  8. IE中的CSS3不完全兼容方案

    摘要: Internet Explorer,其本身也是足够强大的.IE特有的技术可以很好的实现一些CSS3的效果. 到Internet Explorer 8为止,IE系列是不支持CSS3的.在IE中要 ...

  9. 关于在VS 上发布网站

    在vs 上建立的网站只能用 localhost 进行访问,想要自己本机上的网站发布到IIS上面,这样就可以直接用 IP 地址来访问了,那么照如下的方式做: 1. 首先需要使用vs 发布自己的网站 1. ...

  10. Spring详细总结

    Spring的特性之一:IOC(控制反转Inverse Of Control),又称依赖注入,是一种重要的面向对象编程的法则来削减计算机程序的耦合问题 也是轻量级spring框架的核心: 依赖注入: ...