为了更好地理解覆盖索引,在正式介绍覆盖索引之前,首先稍微来谈一谈有关索引的一些基础知识。

数据页和索引页

  在SQLServer中,数据存储的基本单位是页,一页的大小为8KB,分别由页首,数据行和行偏移量组成,如下图结构:

  

  页首固定占用96个字节,用来存储相关的页面系统信息,例如所属的数据库表对象Id等。数据行是真实数据的存储区域,每一行的大小是不固定的。行偏移量是一个数组,数组的每个位置占2个字节,用来存储数据行距离开头的位置偏移量,主要是用来做快速定位,例如想要查找第N行,只要访问行偏移量数组的第N项,就能快速找到数据行所在的位置。索引页和数据页的结构类似,所不同的是索引页的数据行存储的是和索引相关的信息。

聚集索引和非聚集索引

  聚集索引定义了表中数据存储的真实物理位置,它是按照指定列的顺序来存储数据的,类比于新华字典中的汉字是按照拼音顺序排列的,所以每张表只能建立一个聚集索引。聚集索引是一棵B+树结构,包含索引页和数据页,最底下的一排叶子节点是数据页,往上则为索引页,来看一张图应该更清晰一些:

  

  非聚集索引是独立于数据真实存储顺序逻辑而存在的,类比于新华字典中按偏旁部首查找汉字的方式。与聚集索引对比,非聚集索引也是B+树的数据结构,但却只包含索引页,而且在一张表中可以建立多个非聚集索引,有关索引的深入分析可以查看这篇文章。同样来看一张非聚集索引的图:

  

什么是覆盖索引

  覆盖索引是在SQLServer2005中引入的概念,只能建立在非聚集索引的基础上,通常情况下,非聚集索引的索引页是不包含真实数据的,只存储着指向数据页中数据行的指针,而覆盖索引则是通过将数据存储在索引页上,从而在查找对应数据的时候,只要找到索引页就可以访问到数据,无需再去查询数据页,所以说这个索引是数据“覆盖”的。

--覆盖索引的创建是在非聚集索引创建的基础上增加INCLUDE语句
CREATE NONCLUSTERED INDEX {index_name}
ON {table_name}(column_name...) --非聚集索引可以声明指定多个列作为索引项
INCLUDE(column_name...) --覆盖索引可以指定多个列存储在索引页上

创建覆盖索引的语法

覆盖索引分析

  这一小节将通过创建覆盖索引以及使用DBCC命令查看索引的方式进行介绍。

IF DB_ID('Test') IS NULL
BEGIN
CREATE DATABASE Test;
END
GO USE Test;
GO IF OBJECT_ID('t1','U') IS NULL
BEGIN
CREATE TABLE t1
(
t1_id INT NOT NULL IDENTITY(1,1),
t1_name VARCHAR(20) NOT NULL,
t1_name1 VARCHAR(20) NOT NULL,
t1_name2 VARCHAR(20) NOT NULL,
t1_name3 VARCHAR(20) NOT NULL,
t1_name4 VARCHAR(20) NOT NULL,
t1_name5 VARCHAR(20) NOT NULL
);
END /*
*插入测试数据
*/
INSERT INTO t1
( t1_name,
t1_name1,
t1_name2,
t1_name3,
t1_name4,
t1_name5 )
SELECT 'name',
'name',
'name',
'name',
'name',
'name'
FROM sysobjects o1
CROSS JOIN sysobjects o2; /*
*创建覆盖索引
*/
IF NOT EXISTS(SELECT 1
FROM sysindexes
WHERE name='idx_t1_id')
BEGIN
CREATE NONCLUSTERED INDEX idx_t1_id
ON t1(t1_id)
INCLUDE(t1_name);
END

创建表&测试数据&覆盖索引

  执行CROSS JOIN插入的测试数据有4000条左右,现在可以使用DBCC命令来查看表的数据页和索引页的情况。

/*
*查看页的基本信息
*前提条件:表中必须插入了数据
*所需参数:(数据库名,表名,-1表示显示全部IAM页,数据页, 索引页)
*/
DBCC IND (Test,t1,-1);

查看表的数据页和索引页命令

  执行完这条命令后,应该可以看到显示的页信息,其中PageType=1的行表示数据页,PageType=2的行表示索引页,任意选择一条PageType=2的行,找到PageFID和PagePID,就可以使用DBCC命令来查看索引页的具体信息。

/*
*查看索引页的基本信息
*所需参数:(数据库名,PageFID,PagePID,3表示输出每行每列的信息)
*/
DBCC PAGE(Test,1,7732,3);

查看索引页信息的命令

  执行完这条命令后,应该可以看到t1_name这一列的信息是包含在这个索引页中的。现在可以通过执行不同的查询SQL来查看覆盖索引所带来的性能提升,在执行SQL的同时开启显示实际的执行计划,从而可以清楚得看到对比结果。

SELECT t1_name
FROM t1
WHERE t1_id = 500; SELECT t1_name1
FROM t1
WHERE t1_id =500;

对比查询SQL

  

  

  查询1开销为33%,而查询2的开销为67%,对比可以看到查询t1_name的开销比查询t1_name1的开销小很多,因为查询t1_name只需要执行索引,就可以在索引页上找到数据,而查询t1_name1还要去查找数据页。

覆盖索引的思考

  创建索引能带来查询的优化,但却带来了更改数据的负担,覆盖索引也不意外。由上面的分析我们知道,覆盖索引是非聚集索引的进一步细化,在更新数据的时候,如果涉及到覆盖索引INCLUDE的列,除了更改数据页之外还要更改索引页,比单纯使用非聚集索引增添了额外的工作。所以,在设计覆盖索引的时候,要综合考虑应该覆盖的列,确保INCLUDE的列能带来最佳的性能优化。

SQLServer覆盖索引的更多相关文章

  1. SQLSERVER聚集索引与非聚集索引的再次研究(下)

    SQLSERVER聚集索引与非聚集索引的再次研究(下) 上篇主要说了聚集索引和简单介绍了一下非聚集索引,相信大家一定对聚集索引和非聚集索引开始有一点了解了. 这篇文章只是作为参考,里面的观点不一定正确 ...

  2. SQL Server查询性能优化——覆盖索引(二)

    在SQL Server 查询性能优化——覆盖索引(一)中讲了覆盖索引的一些理论. 本文将具体讲一下使用不同索引对查询性能的影响. 下面通过实例,来查看不同的索引结构,如聚集索引.非聚集索引.组合索引等 ...

  3. SQL Server 查询性能优化——覆盖索引

    覆盖索引又可以称为索引覆盖. 解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖. 解释二: 索引是高效找到行的一个方法,当能通过检索索引 ...

  4. mysql覆盖索引与回表

    mysql覆盖索引与回表 Harri2012关注 62019.07.28 11:14:15字数 1,292阅读 77,322 select id,name where name='shenjian' ...

  5. SQLSERVER聚集索引与非聚集索引的再次研究(上)

    SQLSERVER聚集索引与非聚集索引的再次研究(上) 上篇主要说聚集索引 下篇的地址:SQLSERVER聚集索引与非聚集索引的再次研究(下) 由于本人还是SQLSERVER菜鸟一枚,加上一些实验的逻 ...

  6. sqlserver 数据库索引建立原则

    1.始终包含聚集索引 当表中不包含聚集索引时,表中的数据是无序的,这会降低数据检索效率.即使通过索引缩小了数据检索的范围,但由于数据本身是无序的,当从表中提取实际数据时,会产生频繁的定位问题,这也使得 ...

  7. Sql Server 覆盖索引

    覆盖索引通常都是复合索引,即索引字段为多个.创建索引时应该注意索引排列顺序. Sql Server检索应用索引时,字段识别顺序为 从左到右. 例如如下索引的使用上 Create NONCLUSTERE ...

  8. mysql延迟查询, 覆盖索引使用例子

    引用自 'mysql高性能' 5.3.6章节 不能使用覆盖索引的情况 :  解决办法 : 

  9. mongodb 关系、引用、覆盖索引查询

    一.关系 MongoDB 的关系表示多个文档之间在逻辑上的相互联系.文档间可以通过嵌入和引用来建立联系.MongoDB 中的关系可以是:1对1,1对多,多对1,多对多. 一个用户可以用多个地址,这是典 ...

随机推荐

  1. Java基础知识学习笔记(一)

    理解面向对象: Java纯粹的面向对象的程序设计语言,主要表现为Java完全支持面向对象的三个基本特征:继承.封装.多态. Java程序的最小单位是类,类代表客观世界中具有某种特征的一类事物,这些类可 ...

  2. Linux下安装配置 Jdk1.6+Tomcat6+Apache2.2.x+jk_mod1.2 详解

    本篇以Redhat AS5,内核为Linux 2.6.18-8.el5 为例,其中Redhat/Fedora系列基本一致,其他Linux或者版本均可以参考. STEP 1 软件下载:1. jdk1.6 ...

  3. python面向对象-3类的静态方法和类方法

    还是以上次的洗衣机例子: class Washer: company='ZBL' def __init__(self,water=10,scour=2): self._water=water #不想让 ...

  4. HDU 3681 Prison Break (二分 + bfs + TSP)

    题意:给定上一个 n * m的矩阵,你的出发点是 F,你初始有一个电量,每走一步就会少1,如果遇到G,那么就会加满,每个G只能第一次使用,问你把所有的Y都经过,初始电量最少是多少. 析:首先先预处理每 ...

  5. web.xml 404 500 配置

    web.xml <error-page> <error-code>404</error-code> <location>/error404.html&l ...

  6. hdu1158 Employment Planning 2016-09-11 15:14 33人阅读 评论(0) 收藏

    Employment Planning Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

  7. PAT甲 1009. Product of Polynomials (25) 2016-09-09 23:02 96人阅读 评论(0) 收藏

    1009. Product of Polynomials (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yu ...

  8. 如何利用Visio设计一个系统的结构图

    首先建立一个空的vison列表 添加图形和连接线 托选一个矩形块到操作台上,并进行底色填充 选择有向线段1拖到矩形模块上,此时有向线段1会自动吸附到矩形的中点处. 此时按下图操作即可取消,自动吸附 托 ...

  9. ssh远程调用之shell脚本远程调用应用程序

    1.引子 前几天有一个需求是这样的:本机的shell脚本,通过远程调用另一台机子上的shell脚本,来完成对远程机子上分发的Java程序的执行和其他操作.看上去挺容易,实际上也不难. 第一步:用scp ...

  10. 使用VSTS进行单元测试练习

    本次作业要求:练习教科书第22~25页单元测试练习,要求自行安装Visual Studio开发平台,版本至少在2010以上,要求把程序安装过程和练习过程写到博客上,越详细越好,要图文并茂,没有书的同学 ...