9.1 索引概述-1

SQL数据库开发—TSQL—第九章索引

9.1 索引概述

1 索引是与表或视图关联的磁盘上或内存中结构,可以加快从表或视图中检索行的速度。 索引包含由表或视图中的一列或多列生成的键。 对于磁盘上索引,这些键存储在某个结构(B 树)中,使 SQL Server 可以快速高效地找到与键值关联的行。

https://gss3.bdstatic.com/-Po3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=35678d408794a4c21e2eef796f9d70b0/4e4a20a4462309f773bdc15d720e0cf3d6cad6ab.jpg

2 索引在逻辑上以组织为包含行和列的表存储数据;在物理上以按行数据格式(称为行存储),或以按列数据格式(称为列存储)存储数据。

 

3 索引是什么:数据库中的索引类似于一本书的目录,在一本书中使用目录可以快速找到你想要的信息,而不需要读完全书。在数据库中,数据库程序使用索引可以重啊到表中的数据,而不必扫描整个表。书中的目录是一个字词以及各字词所在的页码列表,数据库中的索引是表中的值以及各值存储位置的列表。

4 索引的利弊:查询执行的大部分开销是I/O,使用索引提高性能的一个主要目标是避免全表扫描,因为全表扫描需要从磁盘上读取表的每一个数据页,如果有索引指向数据值,则查询只需要读少数次的磁盘就行啦。所以合理的使用索引能加速数据的查询。

5 索引并不总是提高系统的性能,带索引的表需要在数据库中占用更多的存储空间,同样用来增删数据的命令运行时间以及维护索引所需的处理时间会更长。所以我们要合理使用索引,及时更新去除次优索引。

9.1.1 名词解释

 1 数据的基本结构

一个新表被创建之时,系统将在磁盘中分配一段以8K为单位的连续空间,当字段的值从内存写入磁盘时,就在这一既定空间随机保存,当一个 8K用完的时候,数据库指针会自动分配一个8K的空间。这里,每个8K空间被称为一个数据页(Page),又名页面或数据页面,并分配从0-7的页号, 每个文件的第0页记录引导信息,叫文件头(File header);每8个数据页(64K)的组合形成扩展区(Extent),称为扩展。全部数据页的组合形成堆(Heap)。

SQL规定行不能跨越数据页,所以,每行记录的最大数据量只能为8K。这就是char和varchar这两种字符串类型容量要限制在8K以内的 原因,存储超过8K的数据应使用text类型,实际上,text类型的字段值不能直接录入和保存,它只是存储一个指针,指向由若干8K的文本数据页所组成 的扩展区,真正的数据正是放在这些数据页中。 

页面有空间页面和数据页面之分。  

当一个扩展区的8个数据页中既包含了空间页面又包括了数据或索引页面时,称为混合扩展(Mixed Extent),每张表都以混合扩展开始;反之,称为一致扩展(Uniform Extent),专门保存数据及索引信息。 

表被创建之时,SQL在混合扩展中为其分配至少一个数据页面,随着数据量的增长,SQLS可即时在混合扩展中分配出7个页面,当数据超过8个页面时,则从一致扩展中分配数据页面。  

2 页分裂

一半的数据将保留在老页面,而另一半将放入新页面,并且新页面可能被分配到任何可用的页。所以,频繁页分裂,后果很严重,将使物理表产生大量数据碎片,导致直接造成I/O效率的急剧下降,最后,停止SQL的运行并重建索引将是我们的唯一选择!

3 填充因子

索引的一个特性,定义该索引每页上的可用空间量。FILLFACTOR(填充因子)适应以后表数据的扩展并减小了页拆分的可能性。填充因子是从0到100的百分比数值,设为100时表示将数据页填满。只有当不会对数据进行更改时(例如 只读表中)才用此设置。值越小则数据页上的空闲空间越大,这样可以减少在索引增长过程中进行页分裂的需要,但这一操作需要占用更多的硬盘空间。填充因子指定不当,会降低数据库的读取性能,其降低量与填充因子设置值成反比。

9.1.2 堆(没有聚集索引的表)

堆是不含聚集索引的表。 可在存储为堆的表上创建一个或多个非聚集索引。 数据存储于堆中并且无需指定顺序。 通常,数据最初以行插入表时的顺序存储,但 数据库引擎 可能会在堆中四处移动数据,以便高效地存储行;因此,无法预测数据顺序。 若要确保从堆返回的行的顺序,您必须使用 ORDER BY 子句。 

1 何时使用堆

如果某个表是堆并且不具有任何非聚集索引,则必须检查整个表(表扫描)以便找到任何行。 这在表很小(例如公司 12 个地区办事处的列表)时是可接受的。

2 何时不使用堆

在经常以排序后的顺序返回数据时,不要使用堆。 排序列上的聚集索引可以避免排序操作。

在数据经常组合在一起时,不要使用堆。 数据必须首先进行排序,然后才能分组,并且排序列上的聚集索引可以避免排序操作。

在经常从表查询数据范围时,不要使用堆。 范围列上的聚集索引将避免对整个堆进行排序。

在不存在非聚集索引并且表比较大时,不要使用堆。 在某一堆中,若要找到任何行,必须读取该堆的所有行。

3 管理堆

若要创建堆,请创建没有聚集索引的表。 如果表已具有某一聚集索引,则删除该聚集索引以便将该表返回到某一堆。

若要删除堆,请在该堆上创建聚集索引。

若要重新生成堆以便回收浪费的空间,请在该堆上创建一个聚集索引,然后删除该聚集索引。

 

 

9.2 索引涉及原则

绝大部分人都知道,索引的好处,但是极其少人深刻感受到它的坏处。我一直这么认为,对于SQL Server中的索引(甚至一切数据库管理系统,再甚至世间绝大部分事物)而言,并没有绝对的好或者绝对的坏。就好像给你一把斧头和一个刀片,让你砍一棵树和切割一张纸,你非要用刀片砍树,斧头切纸,然后说刀片和斧头都是烂东西,显然不合理(这不是段子也不是脑筋急转弯,别纠结太多)。

对于OLTP数据库,单表索引不应该过多。根据实际工作经验:

对于核心表(常用表):所有索引不要超过6个。

对于普通表:所有索引不要超过4个。

对于小型表:所有索引不要超过2个。

 

设计索引时,应考虑以下

9.2.1 数据库准则:

1 对表编制大量索引会影响 INSERT、UPDATE、DELETE 和 MERGE 语句的性能,因为当表中的数据更改时,所有索引都须适当调整。 例如,如果在多个索引中使用了某个列,并且执行了修改该列数据的 UPDATE 语句,则必须更新包含该列的每个索引以及基础的基表(堆或聚集索引)中的该列。

 

2 避免对经常更新的表进行过多的索引,并且索引应保持较窄,就是说,列要尽可能少

3 使用多个索引可以提高更新少而数据量大的查询的性能。 大量索引可以提高不修改数据的查询(例如 SELECT 语句)的性能,因为查询优化器有更多的索引可供选择,从而可以确定最快的访问方法。

4 对小表进行索引可能不会产生优化效果,因为查询优化器在遍历用于搜索数据的索引时,花费的时间可能比执行简单的表扫描还长。 因此,小表的索引可能从来不用,但仍必须在表中的数据更改时进行维护。

9.2.2 查询注意事项

设计索引时,应考虑以下查询准则:

1 为经常用于查询中的谓词和联接条件的列创建非聚集索引。 这些是你的 SARGable1 列。 但是,应避免添加不必要的列。 添加太多索引列可能对磁盘空间和索引维护性能产生负面影响。

2 涵盖索引可以提高查询性能,因为符合查询要求的全部数据都存在于索引本身中。 也就是说,只需要索引页,而不需要表的数据页或聚集索引来检索所需数据,因此,减少了总体磁盘 I/O。 例如,对某一表(其中对列 a 、 b 和 c创建了组合索引)的列 a和b 的查询,仅仅从该索引本身就可以检索指定数据。

 重要

覆盖索引是针对非聚集索引的指定,它直接解析一个或几个类似的查询结果,而不访问其基表,并且不会引发查找。 此类索引在叶级别上具有所有必要的非 SARGable 列。 这意味着,由 SELECT 子句以及所有 WHERE 和 JOIN 参数返回的列都被索引所覆盖。 当与表本身的行和列相比,如果索引足够窄,那么执行查询的 I/O 可能会少得多,这意味着它是总列的一个真正子集。 如果选择大型表的一小部分,请考虑覆盖索引,其中的小部分是由一个固定谓词定义,比如一个稀疏列,例如它只包含几个非 NULL 值。

 

3 将插入或修改尽可能多的行的查询写入单个语句内,而不要使用多个查询更新相同的行。 仅使用一个语句,就可以利用优化的索引维护。

4 评估查询类型以及如何在查询中使用列。 例如,在完全匹配查询类型中使用的列就适合用于非聚集索引或聚集索引。

 “SARGable”一词在关系数据库中指的是一个搜索可论证的谓词,它可以利用一个索引来加快查询的执行过程。

9.2.3 列注意事项

设计索引时,应考虑以下列准则:

1 对于聚集索引,请保持较短的索引键长度。 另外,对唯一列或非空列创建聚集索引可以使聚集索引获益。

2 无法指定 ntext、 text、 image、 varchar(max)、 nvarchar(max) 和 varbinary(max) 数据类型的列为索引键列。 不过,varchar(max)、 nvarchar(max)、 varbinary(max) 和 xml 数据类型的列可以作为非键索引列参与非聚集索引。 有关详细信息,请参阅本指南中的 具有包含列的索引。

3 xml 数据类型的列只能在 XML 索引中用作键列。 有关详细信息,请参阅 XML 索引 (SQL Server)。 SQL Server 2012 SP1 引入了称作选择性 XML 索引的一种新的 XML 索引。 这个新的索引可提高 SQL Server 中针对作为 XML 存储的数据的查询性能,从而通过降低索引本身的存储成本来加快大型 XML 数据工作负荷的索引编制和改进可伸缩性。 有关详细信息,请参阅选择性 XML 索引 (SXI)。

4    检查列的唯一性。 在同一个列组合的唯一索引而不是非唯一索引提供了有关使索引更有用的查询优化器的附加信息。

5    在列中检查数据分布。 通常情况下,为包含很少唯一值的列创建索引或在这样的列上执行联接将导致长时间运行的查询。 这是数据和查询的基本问题,通常不识别这种情况就无法解决这类问题。 例如,如果物理电话簿按姓的字母顺序排序,而城市里所有人的姓都是 Smith 或 Jones,则无法快速找到某个人。 有关数据分布的详细信息,请参阅 统计信息。

6考虑对具有定义完善的子集的列(例如,稀疏列、大部分值为 NULL 的列、含各类值的列以及含不同范围的值的列)使用筛选索引。 设计良好的筛选索引可以提高查询性能,降低索引维护成本和存储成本。

7 如果索引包含多个列,则应考虑列的顺序。 用于等于 (=)、大于 (>)、小于 (<) 或 BETWEEN 搜索条件的 WHERE 子句或者参与联接的列应该放在最前面。 其他列应该基于其非重复级别进行排序,就是说,从最不重复的列到最重复的列。

例如,如果将索引定义为 LastName、 FirstName ,则该索引在搜索条件为 WHERE LastName = 'Smith' 或 WHERE LastName = Smith AND FirstName LIKE 'J%'时将很有用。 不过,查询优化器不会将此索引用于基于 FirstName (WHERE FirstName = 'Jane')而搜索的查询。

9.3 索引的分类

1  SQL SERVER中有很多种索引类型。

按存储结构区分:“聚集索引(又称聚类索引,簇集索引)”,“分聚集索引(非聚类索引,非簇集索引)”

按数据唯一性区分:“唯一索引”,“非唯一索引”。

非聚集索引是全表还是经过筛选,使用WHERE 筛选索引。

非聚集索引是否包含列,INCLUDE。

按键列个数区分:“单列索引”,“多列索引”。

还有columnstore,哈希,内存优化非聚集索引。

发布了37 篇原创文章 · 获赞 0 · 访问量 2419

猜你喜欢

转载自blog.csdn.net/syjhct/article/details/86652666
9.1
今日推荐