SQL Server从入门到项目实践(超值版)读书笔记 26
第13章 索引的应用
🎉学习指引:
索引是数据库中帮助数据库操作人员快速查找数据的数据,表中的数据越多,查询数据所花费的时间就越长,如果表中查询的列有一个索引,数据库能快速到达一个位置去搜寻数据,而不必查看所有数据。本章就来介绍索引的使用,主要内容包括认识索引、创建索引、修改索引、删除索引,以及索引的分析与维护等。
13.1 认识索引
索引是一个单独的、存储在磁盘上的数据库结构,它们包含着对数据表里所有记录的引用指针。索引用于快速找出在某个或多个列中有某一特定值的行,对相关列使用索引是降低查询操作时间的最佳途径。
索引包含由表或视图中的一列或多列生成的键。
13.1.1 索引概述
索引设计不合理或者缺少索引都会对数据库和应用程序的性能造成影响。高效的索引对于获得良好的性能非常重要。设计索引时,应该考虑以下准则:
- 索引并非越多越好。一张表中如果由大量索引,不仅占用大量的磁盘空间,而且会影响INSERT、DELETE、UPDATE等语句的性能。因为当表中数据更改的同时,索引也会进行调整和更新。
- 避免对经常更新的表进行过多的索引,并且索引中的列应尽可能少。而对经常用于查询的字段应该创建索引,但要避免添加不必要的字段。
- 数据量小的表最好不要使用索引。由于数据较少,查询花费的时间可能比遍历索引的时间还要短,索引可能不会产生优化效果。
- 在条件表达式中经常用到的,不同值较多的列上建立索引,在不同值较少的列上不要建立索引。例如,在学生表的“性别”字段上只有“男”与“女”两个不同值,因此就无须建立索引。如果建立索引,不但不会提高查询效率,反而会严重降低更新速度。
- 当唯一性是某种数据本身的特征时,指定唯一索引。使用唯一索引能够确保定义的列的数据完整性,提高查询速度。
- 在频繁进行的排序或分组(即进行GROUP BY或ORDER BY操作)的列上建立索引,如果待排序的列有多个,可以在这些列上建立组合索引。
13.1.2 索引的优缺点
在数据库中合理地使用索引可以提高查询数据的速度,下面介绍索引的优缺点。
索引的优点主要有以下4条:
- 通过创建唯一索引,可以保证数据库表中每一行数据的唯一性;
- 可以大大加快数据的查询速度,这也是创建索引的最主要的原因;
- 实现数据的参照完整性,可以加速表和表之间的连接;
- 在使用分组和排序子句进行数据查询时,也可以显著减少查询中分组和排序的时间;
索引的缺点主要有以下3条:
- 创建索引和维护索引要耗费时间,并且随着数据量的增加所耗费的时间也会增加;
- 索引需要占磁盘空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果有大量的索引,索引文件可能比数据文件更快到达最大文件尺寸;
- 当对表中的数据进行增加,删除和修改的时候,索引也要动态地维护,这样就降低了数据的维护速度。
13.1.3 索引的分类
不同的数据库中提供了不同的索引类型,SQL Server中的索引主要有聚集索引、非聚集索引、唯一索引、索引视图、全文索引等。按照存储结构的不同,可以将索引分为聚集索引和非聚集索引两大类。
13.1.3.1 聚集索引
聚集索引基于数据行的键值,在表内排序和存储这些数据行。每个表只能有一个聚集索引,因为数据行本身只能按一个顺序存储。
创建聚集索引时应该考虑以下4个因素:
- 每个表只能有一个聚集索引。
- 表中的物理顺序和索引中行的物理顺序是相同的,创建任何非聚集索引之前要首先创建聚集索引,这是因为非聚集索引改变了表中行的物理顺序。
- 关键值的唯一性使用UNIQUE关键字或者由内部的唯一标识符明确维护。
- 在索引的创建过程中,SQL Server临时使用当前数据库的磁盘空间,所以要保证有足够的空间创建聚集索引。
13.1.3.2 非聚集索引
非聚集索引具有完全独立于数据行的结构,使用非聚集索引不用将物理数据页中的数据按列排序。非聚集索引包含索引键值和指向表数据存储位置的行定位器。
可以对表或索引视图创建多个非聚集索引。通常,设计非聚集索引是为了改善经常使用的、没有建立聚集索引的查询的性能。
查询优化器在搜索数据值时,先搜索非聚集索引以找到数据值在表中的位置,然后直接从该位置检索数据。这使得非聚集索引成为完全匹配查询的最佳选择,因为索引中包含所搜索的数据值在表中的精确位置的项。
具有以下特点的查询可以考虑使用非聚集索引:
- 使用JION或GROUP BY子句。应为连接和分组操作中所涉及的列创建多个非聚集索引,为任何外键列创建一个聚集索引。
- 包含大量唯一值的字段。
- 不返回大型结果集的查询。创建筛选索引以覆盖从大型表中返回定义完善的行子集的查询。
- 经常包含在查询的搜索条件(如返回完全匹配的WHERE子句)中的列。
13.1.3.3 其他索引
除了聚集索引和非聚集索引之外,SQL Server中还提供了其他的索引类型,如下表所示:
索引名称 | 说 明 |
唯一索引 | 确保索引键不包含重复的值,因此,表或视图中的每一行在某种程度上是唯一的。聚集索引和非聚集索引都可以是唯一索引。这种唯一性与前面讲过的主键约束是相关联的,在某种程度上,主键约束等于唯一性的聚集索引。 |
包含列索引 | 一种非聚集索引,它扩展后不仅包含键列,还包含非键列。 |
索引视图 | 在视图上添加索引后能提高视图的查询效率。视图的索引将具体化视图,并将结果集永久存储在唯一的聚集索引中,而且其存储方法与带聚集索引的存储方法相同。创建聚集索引后,可以为视图添加非聚集索引。 |
全文索引 | 一种特殊类型的基于标记的功能性索引,由Microsoft SQL Server全文引擎生成和维护。用于帮助在字符串数据中搜索复杂的词。这种索引的结构与数据库引擎使用的聚集索引或非聚集索引的B树结构是不同的。 |
空间索引 | 一种针对geometry数据类型的列上建立的索引,这样可以更高效地对列中的空间对象执行某些操作。空间索引可以减少需要应用开销相对较大的空间操作的对象数。 |
筛选索引 | 一种经过优化的非聚集索引,尤其适用于涵盖从定义完善的数据子集中选择数据的查询。筛选索引使用筛选谓词对表中的部分行进行索引。与全表索引相比,设计良好的筛选索引可以提高查询性能、减少索引维护开销并可降低索引存储开销。 |
XML索引 | 是与XML数据关联的索引形式,是XML二进制大对象(BLOB)的已拆分持久表示形式,XML索引又可以分为主索引和辅助索引 |
13.2 创建索引
13.2.1 创建索引的语法格式
使用CREATER INDEX语句可以创建索引,在创建索引的语法中包括创建聚集索引和非聚集索引两种方式,用户可以根据实际需要进行选择,语法格式如下:
CREATE [UNIQUE][CLUSTERED|NONCLUSTERED]
INDEX index_name ON {table|view}(column[ASC|DESC][,...n])
[INCLUDE(column_name[,...n])]
[with
(
PAD_INDEX={ON|OFF}
|FILLFACTOR=fillfactor
|SORT_IN_TEMPDB={ON|OFF}
|IGNORE_DUP_KEY={ON|OFF}
|STATISTICS_NORECOMPUTE={ON|OFF}
|DROP_EXISTING={ON|OFF}
|ONLINE={ON|OFF}
|ALLOW_ROW_LOCKS={ON|OFF}
|ALLOW_PAGE_LOCKS={ON|OFF}
|MAXDOP=max_degree_of_parallelism
)[...n]]
主要参数:
- UNQUE:表示在表或视图上创建唯一索引。唯一索引不允许两行具有相同的索引键值。视图的聚集索引必须唯一。
- CLUSTERED:表示创建聚集索引。在创建任何非聚集索引之前创建聚集索引。创建聚集索引时会重新生成表中现有的非聚集索引。如果没有指定CLUSTERED,则创建非聚集索引。
- NONCLUSTERED:表示创建一个非聚集索引,非聚集索引数据行的物理排序独立于索引排序。每个表都最多可包含999个非聚集索引。NONCLUSTERED时CREATE INDEX语句的默认值。
- index_name:指定索引的名称。索引名称在表或视图中必须唯一,但在数据库中不必唯一。
- ON{table|view}:指定索引所属的表或视图。
- column:指定索引基于的一列或多列。指定两个或多个列名,可为指定列的组合值创建组合索引。{table|view}后的括号中,按排序优先级列出组合索引中要包括的列。一个组合索引键中最多可组合16列。组合索引键中的所有列必须在同一张表或视图中。
- [ASC|DESC]:指定特定索引列的升序或降序排列方向。默认值为ASC(升序)。
- INCLUDE(column_name[,...n]):指定要添加到非聚集索引的页级别的非键列。
- PAD_INDEX:表示指定索引填充。默认值为OFF。ON值表示fillfactor指定的可用空间百分比应用于索引的中间级页。
- FILLFACTOR=fillfactor:指定一个百分比,表示在索引创建或重新生成过程中数据库引擎应使每个索引的页级别达到的填充程度。fillfactor必须为介于1~100的整数值,默认为0。
- SORT_IN_TEMPDB:指定是否在tempdb中存储临时的排序结果。默认值为OFF。ON值表示在tempdb中存储用于生成索引的中间排序结果。OFF表示中间排序结果与索引存储在同一数据库中。
- IGNORE_DUP_KEY:指定对唯一聚集索引或唯一非聚集索引执行多行插入操作时,出现重复键值的错误响应。默认值为OFF。ON表示发出一条警告信息,但只有违反了唯一索引的行才会失败。OFF表示发出错误信息,并回滚整个INSERT事务。
- STATISTICS_NORECOMPUTE:指定是否重新计算分发统计信息。默认值为OFF。ON表示不会自动重新计算过时的统计信息。OFF表示启用统计信息自动更新功能。
- DROP_EXISTING:指定应删除并重新生成已命名的先前存在的聚集或非聚集索引。默认值为OFF。ON表示删除并重新生成现有索引。指定的索引名称必须与当前的现有索引相同;但可以修改索引定义。例如,可以指定不同的列、排序顺序、分区方案或索引选项。OFF表示如果指定的索引名已存在,则会显示一条错误。
- ONLINE={ON/OFF}:指定在索引操作期间,基础表和关联的索引是否可以用于查询和数据修改操作,默认值为OFF。
- ALLOW_ROW_LOCKS:指定是否允许行锁。默认值为ON。ON表示在访问索引时允许行锁。数据库引擎确定何时使用行锁。OFF表示未使用行锁。
- ALLOW_PAGE_LOCKS:指定是否允许页锁。默认值为ON。ON表示在访问索引时允许页锁。数据库引擎确定何时使用页锁。OFF表示未使用页锁。
- MAXDOP:指定在索引操作期间,覆盖“最大并行度”配置选项。使用MAXDOP可以限制在执行并计划的过程中使用的处理器数量,最大数量为64个。
13.2.2 使用SQL创建聚集索引
为了演示创建索引的方法,我们先创建一个简单的作者信息数据表AuthorInfo。
正好,我们一起复习复习表的创建:
CREATE TABLE AuthorInfo
(Id BIGINT IDENTITY(1,1) NOT NULL,--序号从1开始,自增1Name VARCHAR(20) NOT NULL,Gender TINYINT NOT NULL,Age INT NOT NULL,Phone VARCHAR(15) NULL,Remark VARCHAR(100) NULL
)
点击“执行”按钮,生成表AuthorInfo。
下面使用SQL语句创建聚集索引,使用CREATE UNIQUE CLUSTERED INDEX语句创建唯一性聚集索引。
例:在AuthorInfo表中的Phone字段上,创建一个名称为IDX_Phone的唯一聚集索引,降序排列,填充因子为30%,输入以下语句:
CREATE UNIQUE CLUSTERED INDEX IDX_Phone --创建名称为IDX_Phone的聚集索引
ON AuthorInfo (Phone DESC) --在表AuthorInfo的Phone字段上,降序排列
WITH
FILLFACTOR=30 --填充度30%
点击“执行”后,即可完成聚集索引的创建。
13.2.3 使用SQL创建非聚集索引
非聚集索引在一张数据表中可以存在多个,并且在创建非聚集索引时,可以不将其列设置成唯一索引,创建非聚集索引的SQL语句如下:CREATE UNIQUE NONCLUSTERED INDEX。
例:在AuthorInfo表中的Name字段上,创建一个名称为IDX_Name的唯一非聚集索引,升序排列,填充因子为10%,SQL语句如下
CREATE UNIQUE NONCLUSTERED INDEX IDX_Name
ON AuthorInfo (Name)
WITH
FILLFACTOR=10
点击“执行”后,即可完成非聚集索引的创建。
13.2.4 使用SQL创建复合索引
所谓复合索引就是指在一张表中创建索引时,索引列可以由多个字段组成,有时也被称作组合索引。
例:在AuthorInfo表中的name和gender列上,创建一个名称为IDX_NameGender的唯一非聚集组合索引,升序排列,填充因子为20%,SQL语句如下:
CREATE UNIQUE NONCLUSTERED INDEX IDX_NameGender
ON AuthorInfo (Name,Gender)
WITH
FILLFACTOR=20
点击“执行”后,即可完成非聚集组合索引的创建。
13.2.5 在SSMS中创建索引
创建索引的语法中,有些关键字是比较难记的,这时就可以在SSMS中以界面方式来创建索引,具体步骤如下:
步骤1:启动SSMS并连接到数据库,在对象资源管理器中,找到将要创建索引的数据库中的表,这里以表employee为例,打开该结点下面的子结点,右击“索引”结点,在弹出的快捷菜单中选择“新建索引”→“非聚集索引”命令。
步骤2:打开“新建索引”窗口,在“常规”选项卡中,可以配置索引的名称和是否唯一。
步骤3:单击“添加”按钮,打开选择添加索引的列窗口,从中选择要添加索引的表中的字段,这里选择在数据类型为varchar的Name字段上添加索引。
步骤4:选择完毕之后,单击“确定”按钮,返回“新建索引”窗口。
步骤5:单击该窗口中的“确定”按钮,返回“对象资源管理器”窗口之后,可以在结点下查看到名称为Index_name的新索引,说明该索引创建成功。
13.3 修改索引
索引创建后,如果不能满足需要,可以对其进行修改,但是不能修改该索引中的全部内容。
用户可以用SQL语句或SSMS两种方式来修改。
13.3.1 修改索引的语法格式
修改索引的语法格式与创建索引的语法格式有很大的差异:
ALTER INDEX index_name
ON
{[database_name].table_or_view_name
}
{[REBUILD][with(<rebuild_index_option>[,...n])][DISABLE][REORGANIZE][PARTITION=partition_number]
}
主要参数说明:
- index_name:要修改的索引名称。
- database_name:索引所在的数据库名称。
- table_or_view_name:表或视图的名称。
- REBUILD:使用相同的规则生成索引。
- DISABLE:将禁用索引。
- PARTITION:执行将重新组织的索引。
从修改索引的语法规则可以看出,修改索引只是对原有索引进行禁用、重新生成等操作,并不是直接修改原有索引的表或列。
13.3.2 禁用不需要的索引
索引可以帮助用户提高查询数据的速度,但有时一张数据表中创建了多个索引,会造成对空间的浪费,因此,有时需要将一些暂时不用的索引禁用掉,当再次需要时再启用该索引。
例:禁用AuthorInfo表中名称为IDX_NameGender的索引,语句如下:
ALTER INDEX IDX_NameGender
ON AuthorInfo
DISABLE
单击“执行”按钮,即可禁用AuthorInfo表中名称为IDX_NameGender的索引
当用户希望使用该索引时,使用启用的语句启用该索引即可,启用的方法是将语句中的DISABLE更换为ENABLE即可。
那么,问题来了,如何才能知道哪些索引被禁用呢?
这时可以通过系统视图sys.indexes来查询,为了能简洁的看出结果,我们只需要查询字段名和是否禁用两列:
SELECT name,is_disabled FROM sys.indexes WHERE is_disabled=1
单击“执行”按钮,即可完成查询,结果如图,1代表禁用,0代表启用。
13.3.3 重新生成新的索引
重新生成新的索引实际上就是将原来的索引删除掉,再创建一个新的索引。重新生成新索引的好处时可以减少获取所请求数据所需的页读取数,以便提高磁盘性能。重新生成新索引使用的是修改索引语法中的REBUILD关键字来实现的。
例:在AuthorInfo表中重新生成名称为IDX_NameGender的索引。语法如下:
ALTER INDEX IDX_NameGender
ON AuthorInfo
REBUILD
单击“执行”按钮,即可完成重新生成索引的操作。
13.3.4 重命名索引的名称
使用系统存储过程sp_rename可以修改索引的名称,其语法格式如下
sp_rename 'object_name','new_name','object_type'
主要参数:
- object_name:用户对象或数据类型的当前限定或非限定名称。此对象可以是表、索引、列、别名数据类型或用户定义类型。
- new_name:指定对象的新名称。
- object_type:指定修改的对象类型。
例:将Authorsinfo表中的索引名称IDX_NameGender更改为fuhe_index,输入语句如下:
exec sp_rename 'authorsinfo.idx_namegender','fuhe_index','index'
13.3.5 在SSMS中修改索引
在SSMS中可以以界面方式修改索引,包括禁用索引、重新生成索引以及重命名索引。
具体操作步骤如下:
步骤1:启动SSMS并连接到数据库,在“对象资源管理器”窗口中,打开“数据库”结点下面要创建索引的数据表结点,例如,这里选择AuthorInfo表,打开该结点下面的子结点,选择需要禁用的索引,右击鼠标,在弹出的快捷菜单中选择“禁用”菜单命令。
步骤2:弹出“禁用索引”窗口,在其中可以查看要禁用的索引列表,单击“确定”按钮,即可完成禁用索引的操作。
步骤3:如果想要重新生成索引,可以在“索引”结点下选择禁用的索引,右击鼠标,在弹出的快捷菜单中选择“重新生成”选项。
步骤4:在弹出的“重新生成索引”窗口中,查看并点击“确定”按钮,即可完成重新生成索引的操作。
步骤5:如果想要重命名索引,可以在“索引”结点下选择要重命名的索引,右击鼠标,在弹出的快捷菜单中选择“重命名”选项。
步骤6:进入索引重命名工作状态,在其中输入新的名称,然后单击“对象资源管理器”窗口中的任意位置,即可完成重命名索引的操作。
13.4 查询索引
索引创建成功后,用户还可以查询数据表中创建的索引信息,下面介绍查询索引信息的方法:
13.4.1 使用系统存储过程查询索引
使用系统存储过程sp_helpindex可以查看数据表或视图中的索引信息
sp_helpindex [@objname=] 'name'
其中,[@objname=] 'name':用户定义的表或视图的限定或非限定名称。仅当指定限定的表或视图名称时,才需要使用引号。
如果提供了完全限定的名称,包括数据库名称,则该数据库名称必须是当前数据库的名称。
例:使用存储过程查看数据库mydatabase中表AuthorInfo定义的索引信息
exec sp_helpindex 'AuthorInfo'
单击“执行”按钮,即可完成索引信息的查询,由执行结果可以看到如下参数:
- index_name:索引名称
- index_description:索引的描述信息
- index_keys:索引所在表的列
13.4.2 在SSMS中查看索引
除使用系统存储过程查询索引信息外,用户还可以在SSMS中查看索引信息,具体方法为:
步骤1:在“对象资源管理器”窗口中,打开指定数据库结点,然后选择该数据库中的表,并展开该表中的索引结点;
步骤2:选中索引项,右键鼠标,在弹出的快捷菜单中选择“属性”命令,或双击该索引项;
步骤3:打开“索引属性”窗口,在该窗口中查看索引的相关信息,还可以修改索引的名称,类型等信息。
13.4.3 查看索引的统计信息
索引信息还包括统计信息,这些信息可以用来分析索引性能,更好地维护索引。
索引统计信息是查询优化器,用来分析和评估查询、制定最优查询方式的基础数据,用户可以在SSMS中查看索引统计信息,也可以使用DBCC SHOW_STATISTICS命令来查看指定索引的信息。
13.4.3.1 在SSMS中查看索引统计信息
步骤1:在“对象资源管理器”中,展开表AuthorInfo的“统计信息”结点,选择要查看统计信息的索引;
步骤2:右击鼠标,在弹出的快捷菜单中选择“属性”命令;
步骤3:打开“统计信息属性”窗口,选择“选项页”中的“详细信息”选项,可以在右侧的窗格中看到当前索引的统计信息。
13.4.3.2 使用BDCC SHOW_STATISTICS命令查看
用户还可以使用 BDCC SHOW_STATISTICS命令来返回指定表或视图中特定对象的统计信息,这些对象可以是索引、列等。
例:使用BDCC SHOW_STATISTICS命令来查看AuthorInfo表中IDX_phone索引的统计信息,输入语句如下:
DBCC SHOW_STATISTICS ('mydatabase.dbo.AuthorInfo',IDX_phone)
单击“执行”按钮,即可完成索引统计信息的查看
返回的统计信息包含三个部分:统计标题信息、统计密度信息和统计直方图信息。
统计标题信息主要包括表中的行数、统计抽样行数、索引列的平均长度等。
统计密度信息主要包括索引列前缀集选择性、平均长度等信息。
统计直方图信息即为显示直方图时的信息。
13.5 删除索引
在数据库中使用索引,既可以给数据库的管理带来好处,也会造成数据存储中的浪费。因此,当表中的索引不再需要时,就需要及时将这些索引删除。
13.5.1 删除索引的语法
使用DROP语句可以删除索引,语法如下:
DROP INDEX
{index_name ON
{
[datebase_name.[schema_name].[schema_name]
table_or_view_name
}
[,...n]
|[owner_name.] table_or_view_name.index_name
[,...n]
}
主要参数:
- index_name:索引名称
- datebase_name:数据库名称
- schema_name:表或视图所属架构名称
- table_or_view_name:与该索引关联的表或视图名称
13.5.2 一次删除一个索引
从删除索引的语法可以看出,在删除索引时,可以一次删除一个索引,也可以同时删除多个索引。
例:删除数据表AuthorInfo中的IDX_NameGender索引
DROP INDEX IDX_NameGender ON dbo.AuthorInfo
13.5.3 一次删除多个索引
当需要删除多个索引时,只需要把多个索引名依次写在DROP INDEX后面即可。
例:一次删除数据表AuthorInfo中的IDX_NameGender和IDX_Phone索引
DROP INDEX IDX_NameGender ON dbo.AuthorInfo,IDX_Phone ON dbo.AuthorInfo
13.5.4 在SSMS中删除索引
在SSMS中可以以界面方式修改索引,包括禁用索引、重新生成索引和重命名索引。
具体操作步骤如下:
步骤1:在“对象资源管理器”窗口中,打开“数据库”结点下面要删除索引的数据表结点,打开该结点下面的子结点,选择需要删除的索引,右击鼠标,在弹出的快捷菜单中选择“删除”命令。
步骤2:弹出“删除对象”对话框,在其中显示了需要删除的所有对象,单击“确定”按钮,即可完成索引的删除操作。