还剩18页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
SQL索引工作原理2022-11-2015:26SQL当一个新表被创建之时,系统将在磁盘中安排一段以8K为单位的连续空间,当字段的值从内存写入磁盘时,就在这一既定空间随机保存,当一个8K用完的时候,SQLS指针会自动安排一个8K的空间这里,每个8K空间被称为一个数据页Page又名页面或数据页面,并安排从0-7的页号,每个文件的第0页纪录引导信息,叫文件头Fileheader;每8个数据页64K的组合形成扩展区Extent称为扩展全部数据页的组合形成堆Heap\SQLS规定行不能跨越数据页,所以,每行纪录的最大数据量只能为8K这就是char和varchar这两种字符串类型容量要限制在8K以内的缘由存储超过8K的数据应使用text类型,实际上,text类型的字段值不能直接录入和保存,它只是存储一个指针,指向由若干8K的文本数据页所组成的扩展区真正的数据正是放在这些数据页中页面有空间页面和数据页面之分当一个扩展区的8个数据页中既包含了空间页面又包括了数据或索引页面时,称为混合扩展MixedExtent,每张表都以混合扩绽开头;反之,称为全都扩展特地保存数据及索引信息表被创建之时,SQLS在混合扩展中为其安排至少一个数据页面,随着数据量的增长,SQLS可即时在混合扩展中安排出7个页面,当数据超过8个页面时,则从全都扩展中安排数据页面空间页面特地负责数据空间的安排和管理,包括PFS页面Pagefreespace:纪录一个页面是否已安排、位于混合扩展还是全都扩展以及页面上还有多少可用空间等信息;GAM页面Globalallocationmap齐口SGAM页面Secodaryglobalallocationmap:最为科学的检索方法也就是说,在只建立了非聚集索引的状况下,每个叶级节点指明白纪录的行定位符RID;而在既有聚集索引又有非聚集索引的状况下,每个叶级节点所指向的是该聚集索引的索引键值,即数据纪录本身假设聚集索引建立在Lastname±而非聚集索引建立在Firstname上,当执行Select*FromMemberWhereFirstname=fM汰e时,查询过程是:®SQLS查询INDID值为2:
②马上从根动身,在Firstname的非聚集索引的非叶级节点中定位最接近Mike的值Jose条目;
③从Jose条目下的叶级页面中查到Mike规律位置一一不是RID而是聚集索引的指针;
④依据这一指针所指示位置,直接进入位于Lastname的聚集索引中的叶级页面中到达Mike数据纪录本身;
⑤将该纪录返回客户端这就完全和我们在“索引的基本概念”中讲到的现实场景完全一样了,当数据发生更新的时候,SQLS只负责对聚集索引的健值驾以维护,而不必考虑非聚集索引,只要我们在ID类的字段上建立聚集索引,而在其它常常需要查询的字段上建立非聚集索引,通过这种科学的、有针对性的在一张表上分别建立聚集索引和非聚集索引的方法,我们既享受了索引带来的敏捷与快捷,又相对规避了维护索引所导致的大量的额外资源消耗
六、索引的优点和不足索引有一些先天不足1:建立索引,系统要占用大约为表的
1.2倍的硬盘和内存空间来保存索引2:更新数据的时候,系统必需要有额外的时间来同时对索引进行更新,以维持数据和索引的全都性——这就犹如图书馆要有特地的位置来摆放索引柜,并且每当库存图书发生变化时都需要有人将索引卡片重整以保持索引与库存的全都当然建立索引的优点也是显而易见的在海量数据的状况下,假如合理的建立了索引,则会大大加强SQLS执行查询、对结果进行排序、分组的操作效率实践表明,不恰当的索引不但于事无补,反而会降低系统性能由于大量的索引在进行插入、修改和删除操作时比没有索引花费更多的系统时间比如在如下字段建立索引应当是不恰当的
1、很少或从不引用的字段;
2、规律型的字段,如男或女(是或否)等综上所述,提高查询效率是以消耗肯定的系统资源为代价的,索引不能盲目的建立,必需要有统筹的规划,肯定要在加快查询速度与降低修改速度”之间做好平衡,有得必有失,此消则彼长这是考验一个DBA是否优秀的很重要的指标上期,我们就索引的基本概念和数据查询原理作了具体阐述,知道了建立索引时肯定要在加快查询速度”与降低修改速度”之间做好平衡,有得必有失,此消则彼长那么,SQLS维护索引时毕竟怎样消耗资源?应当从哪些方面对索引进行管理与优化?以下从六个方面来回答这些问题一.页分裂微软MOC教育我们当一个数据页达到了8K容量,假如此时发生插入或更新数据的操作,将导致页的分裂(又名页拆分).有聚集索引的状况下聚集索引将被插入和更新的行指向特定的页,该页由聚集索引关键字打算;.只有堆的状况下只要有空间就可以插入新的行,但是假如我们对行数据的更新需要更多的空间,以致大于当前页的可用空间,行就被移到新的页中,并且在原位置留下一个转发指针,指向被移动的新行,假如具有转发指针的行又被移动了,那么原来的指针将重新指向新的位置;.假如堆中有非聚集索引,那么尽管插入和更新操作在堆中不会发生页分裂,但是在非聚集索引上仍旧产生页分裂、无论有无索引,大约一半的数据将保留在老页面,而另一半将放入新页面,并且新页面可能被安排到彳到可可用的页所以,频繁页分裂,后果很严峻,将使物理表产生大量数据碎片,导致直接造成I/O效率的急剧下降,最终,不得不停止SQLS的运行并重建索引.填充因子然而在混沌之初,就可以在肯定程度上避开不开心消失在创建索引时,可以为这个索引指定一个填充因子以便在索引的每个叶级页面上保留肯定百分比的空间,将来数据可以进行扩充和削减页分裂填充因子是从0到100的百分比数值,设为100时表示将数据页填满,只有当不会对数据进行更改时(例如只读表中)才用此设置值越小则数据页上的空闲空间越大,这样可以削减在索引增长过程中进行页分裂的需要,但这一操作需要占用更多的硬盘空间填充因子只在创建索引时执行,索引创建以后,当表中进行数据的添加、删除或更新时,是不会保持填充因子的,假如想在数据页上保持额外的空间则有悖于使用填充因子的本意,由于随着数据的输入,SQLS必需在每个页上进行页拆分,以保持填充因子指定的空闲空间因此,只有在表中的数据进行了较大的变动,才可以填充数据页的空闲空间这时,可以从容的重建索引,重新指定填充因子,重新分布数据反之,填充因子指定不当,就会降低数据库的读取性能,其降低量与填充因子设置值成反比例如,当填充因子的值为50时,数据库的读取性能会降低两倍所以,只有在表中依据现有数据创建新索引,并且可以预见将来会对这些数据进行哪些更改时,设置填充因子才有意义.两道数学题假定数据库设计没有问题,那么是否像上篇分析的那样,当你建立了众多的索引,在查询工作中SQLS就只能依据最高指示用索引处理每一个提交的查询呢?答案是否定的数据是怎样被访问的一文中提到的四种索引方案只是一种静态的、标准的和理论上的分析比较实际上,SQLS几乎完全是自主”的打算是否使用索引或使用哪一个索引这是怎么回事呢?让我们先来算一道题假如某表的一条纪录在磁盘上占用1000字节1K的话,我们对其中10字节的一个字段建立索引那么该纪录对应的索引大小只有10字节
0.01K上篇说过,SQLS的最小空间安排单元是页Page『,一个页面在磁盘上占用8K空间所以一页只能存储8条〃纪录,但可以存储800条〃索引现在我们要从一个有8000条纪录的表中检索符合某个条件的纪录(有Where子句),假如没有索引的话,我们需要遍历8000条xlOOO字节/8K字节二1000个页面才能够找到结果假如在检索字段上有上述索引的话,那么我们可以在8000条xlO字节/8K字节=10个页面中就检索到满意条件的索引块,然后依据索引块上的指针逐一找到结果数据块,这样I/O访问量确定要少得多然而有时用索引比不用索引还快同上,假如要无条件检索全部纪录(不用Where子句),不用索引的话,需要访问8000条x1000字节/8K字节=1000个页面;而使用索引的话,首先检索索引,访问8000条xlO字节/8K字节=10个页面得到索引检索结果,再依据索引检索结果去对应数据页面由于是检索全部数据,所以需要再访问8000条x1000字节/8K字节=1000个页面将全部数据读取出来一共访问了1010个页面,这明显不如不用索引快SQLS内部有一套完整的数据索引优化技术,在上述状况下,SQLS会自动使用表扫描的方式检索数据而不会使用任何索引那么SQLS是怎么知道什么时候用索引,什么时候不用索引的呢由于SQLS除了维护数据信息外,还维护着数据统计信息四.统计信息打开企业管理器,单击Database节点右击Northwind数据库一单击“属性一选择Options选项卡,观看Settings下的各项复选项,你发觉了什么从Settings中我们可以看到,在数据库中5QLS将默认的自动创建和更新统计信息这些统计信息包括数据密度和分布信息,正是它们关心SQLS确定最佳的查询策略建立查询方案和是否使用索引以及使用什么样的索引在创建索引时,SQLS会创建分布数据页来存放有关索引的两种统计信息分布表和密度表查询优化器使用这些统计信息估算使用该索引进行查询的成本Cost并在此基础上推断该索引对某个特定查询是否有用随着表中的数据发生变化,SQLS自动定期更新这些统计信息采样是在各个数据页上随机进行从磁盘读取一个数据页后,该数据页上的全部行都被用来更新统计信息统计信息更新的频率取决于字段或索引中的数据量以及数据更改量比如,对于有一万条纪录的表,当1000个索引键值发生转变时,该表的统计信息便可能需要更新,由于1000个值在该表中占了10%这是一个很大的比例而对于有1千万条纪录的表来说,1000个索引值发生更改的意义则可以忽视不计因此统计信息就不会自动更新五.索引的人工维护上面讲到某些不合适的索引将影响到SQLS的性能,随着应用系统的运行,数据不断地发生变化,当数据变化达到某一个程度时将会影响到索引的使用这时需要用户自己来维护索引随着数据行的插入、删除和数据页的分裂,有些索引页可能只包含几页数据,此外应用在执行大量I/O的时候,重建非聚聚集索引可以维护I/O的效率重建索引实质上是重新组织B树需要重建索引的状况有.数据和使用模式大幅度变化;.排序的挨次发生转变;.要进行大量插入操作或已经完成;.使用I/O查询的磁盘读次数比预料的要多;.由于大量数据修改,使得数据页和索引页没有充分使用而导致空间的使用超出估算;.dbcc检查出索引有问题六.索引的使用原则接近尾声的时候,让我们再从另一个角度熟悉索引的两个重要属性----惟一性索引和复合性索引惟一性索引保证在索引列中的全部数据是惟一的,不会包含冗余数据假如表中已经有一个主键约束或者惟一性约束,那么当创建表或者修改表时,SQLS自动创建一个惟一性索引但出于必需保证惟一性那么应当创建主键约束或者惟一性键约束,而不是创建一个惟一性索引复合索引就是一个索引创建在两个列或者多个列上在搜寻时,当两个或者多个列作为一个关键值时,最好在这些列上创建复合索引当创建复合索引时,应当考虑这些规章最多可以把16个列合并成一个单独的复合索引,构成复合索引的列的总长度不能超过900字节;在复合索引中,全部的列必需来自同一个表中,不能跨表建立复合列;在复合索引中,列的排列挨次是特别重要的,原则上,应当首先定义最惟一的列,例如在COL1COL2上的索引与在COL2COL1上的索引是不相同的,由于两个索引的列的挨次不同;为了使查询优化器使用复合索引,查询语句中的WHERE子句必需参考复合索引中第一个列综上所述,我们总结了如下索引使用原则.规律主键使用惟一的成组索引,对系统键作为存储过程采纳惟一的非成组索引,对任何外键列采纳非成组索弓I考虑数据库的空间有多大,表如何进行访问,还有这些访问是否主要用作读写;.不要索引memo/note字段,不要索引大型字段有很多字符,这样作会让索引占用太多的存储空间;.不要索引常用的小型表;用来纪录空闲的扩展或含有空闲页面的混合扩展的位置SQLS综合采用这三种类型的页面文件在必要时为数据表创建新空间;数据页或索引页则特地保存数据及索引信息,SQLS使用4种类型的数据页面来管理表或索引它们是IAM页、数据页、文本/图像页和索引页在WINDOWS中我们对文件执行的每一步操作在磁盘上的物理位置只有系统system才知道;SQLSERVER沿袭了这种工作方式,在插入数据的过程中,不但每个字段值在数据页面中的保存位置是随机的,而且每个数据页面在堆中的排列位置也只有系统system才知道这是为什么呢?众所周知,OS之所以能管理DISK是由于在系统启动时首先加载了文件安排表FATFileAllocationTable正是由它管理文件系统并纪录对文件的一切操作,系统才得以正常运行;同理,作为管理系统级的SQLSERVER也有这样一张类似FAT的表存在它就是索引分布映像页IAMIndexAllocationMap\IAM的存在使SQLS对数据表的物理管理有了可能IAM页从混合扩展中安排,纪录了8个初始页面的位置和该扩展区的位置,每个IAM页面能管理512000个数据页面,如果数据量太大,SQLS也可以增加更多的IAM页可以位于文件的任何位置第一个IAM页被称为FirstlAM其中纪录了以.一般不要为小型数据表设置过多的索引,假如常常有插入和删除操作就更不要设置索引,由于SQLS对插入和删除操作供应的索引维护可能比扫描表空间消耗的时间更多查询是一个物理过程,表面上是SQLS在东跑西跑,其实真正大部分压公路的工作是由磁盘输入输出系统I/O完成,全表扫描需要从磁盘上读表的每一个数据页,假如有索引指向数据值,则I/O读几次磁盘就可以了但是,在随时发生的增、删、改操作中,索引的存在会大大增加工作量,因此合理的索引设计是建立在对各种查询的分析和猜测上的,只有正确地使索引与程序结合起来,才能产生最佳的优化方案SQLS是一个很简单的系统,让索引以及查询背后的东西真相大白,可以关心我们更为深刻的了解我们的系统一句话,索引就像盐,少则无味多则咸后的IAM页的位置数据页和文本/图像页互反,前者保存非文本/图像类型的数据,由于它们都不超过8K的容量,后者则只保存超过8K容量的文本或图像类型数据而索引页顾名思义,保存的是与索引结构相关的数据信息了解页面的问题有助我们下一步精确理解SQLS维护索引的方式,如页拆分、填充因子等
二、索引的基本概念什么是索引呢索引是一种特别类型的数据库对象,它与表有着亲密的联系索引是为检索而存在的如一些书籍的末尾就特地附有索引,指明白某个关键字在正文中的消失的页码位置,便利我们查找,但大多数的书籍只有名目,名目不是索引,只是书中内容的排序,并不供应真正的检索功能可见建立索引要单独占用空间;索引也并不是必需要建立的,它们只是为更好、更快的检索和定位关键字而存在再进一步说我们要在图书馆中查阅图书,该怎么办呢?图书馆的前台有很多叫做索引卡片柜的小柜子,里面分了若干的类别供我们检索图书,比如你可以用书名的笔画挨次或者拼音挨次作为查找的依据,你还可以从作者名的笔画挨次或拼音挨次去查询想要的图书,反正有很多检索方式,但有一点很明白,书库中的书并没有依据这些卡片柜中的挨次排列一虽然理论上可以这样做,事实上,全部图书的脊背上都人工的粘贴了一个特定的编号
①,它们是以这个挨次在排列索引卡片中并没有指明这本书摆放在书库中的第几个书架的第几本,仅仅指明白这个特定的编号管理员则依据这一编号将恳求的图书返回到读者手中这是很形象的例子,以下的讲解将会反复用到它SQLS在安装完成之后,安装程序会自动创建master、model、tempdb等几个特别的系统数据库,其中master是SQLS的主数据库,用于保存和管理其它系统数据库、用户数据库以及SQLS的系统信息,它在SQLS中的地位与WINDOWS下的注册表相当master中有一个名为sysindexes的系统表,特地管理索引SQLS查询数据表的操作都必需用到它,毫无疑义,它是本文主角之一查看一张表的索引属性,可以在查询分析器中使用以下命令select*fromsysindexeswhereid=object_idtablename;而要查看表的索引所占空间的大小可以使用系统存储过程命令sp_spaceusedtablename其中参数tablename为被索引的表名
三、平衡树假如你通过书后的索引知道了一个关键字所在的页码,你有可能通过随机的翻寻,最终到达正确的页码但更科学更快捷的方法是首先把书翻到或许二分之一的位置,假如要找的页码比该页的页码小,就把书向前翻到四分之一处,否则,就把书向后翻到四分之三的地方,依此类推,把书页续分成更小的部分,直至正确的页码这叫两分法,微软在官方教程MOC里另有一种说法叫B树B-TreeBalanceTree即平衡树一个表索引由若干页面组成,这些页面构成了一个树形结构B树由根〃root开头,称为根级节点,它通过指向此外两个页,把一个表的纪录从规律上分成两个部分枝一--非叶级节点(Non-LeafLevel);而非叶级节点又分别指向更小的部分叶——叶级节点(LeafLevel\根节点、非叶级节点和叶级节点都位于索引页中,统称为索引节点,属于索引页的范筹这些枝、叶最终指向了具体的数据页(PageI在根级节点和叶级节点之间的叶又叫数据中间页根(root)对应了sysindexes表的Root字段其中记载了非叶级节点的物理位置(即指针);非叶级节点位于根节点和叶节点之间,记载了指向叶级节点的指针;而叶级节点则最终指向数据页这就是“平衡树
四、聚集索引和非聚集索引从形式上而言,索引分为聚集索引(ClusteredIndexes并口非聚集索引(NonClusteredIndexes\聚集索引相当于书籍背背上那个特定的编号假如对一张表建立了聚集索引,其索引页中就包含着建立索引的列的值(下称索引键值),那么表中的纪录将依据该索引键值进行排序比如,我们假如在姓名这一字段上建立了聚集索引,则表中的纪录将依据姓名进行排列;假如建立了聚集索引的列是数值类型的,那么纪录将依据该键值的数值大小来进行排列非聚集索引用于指定数据的规律挨次,也就是说,表中的数据并没有依据索引键值指定的挨次排列,而仍旧依据插入纪录时的挨次存放其索引页中包含着索引键值和它所指向该行纪录在数据页中的物理位置,叫做行定位符(RID:RowID\好像书后面的的索引表,索引表中的挨次与实际的页码挨次也是不全都的而且一本书或许有多个索引比如主题索引和作者索引SQLServer在默认的状况下建立的索引是非聚集索引,由于非聚集索引不对表中的数据进行重组,而只是存储索引键值并用一个指针指向数据所在的页面一个表假如没有聚集索弓I时,理论上可以建立249个非聚集索引每个非聚集索引供应访问数据的不同排序挨次
五、数据是怎样被访问的若能真正理解了以上索引的基础学问,那么再回头来看索引的工作原理就简洁和轻松多了-SQLS怎样访问没有建立任何索引数据表Heap译成汉语叫做“堆;其本义暗含杂乱无章、无序的意思,前面提到数据值被写进数据页时,由于每一行纪录之间并没地有特定的排列挨次,所以行与行的挨次就是随机无序的,当然表中的数据页也就是无序的了,而表中全部数据页就形成了堆丁可以说一张没有索引的数据表就像一个只有书柜而没有索引卡片柜的图书馆,书库里面塞满了一堆乱七八糟的图书当读者对管理员提交查询恳求后,管理员就一头钻进书库,对比查找内容从头开头一架一柜的逐本查找,运气好的话,在第一个书架的第一本书就找到了,运气不好的话,要到最终一个书架的最终一本书才找到SQLS在接到查询恳求的时候,首先会分析sysindexes表中一个叫做索引标志符(INDID:IndexID)的字段的值,假如该值为0表示这是一张数据表而不是索引表,SQLS就会使用sysindexes表的另一个字段也就是在前面提到过的FirstlAM值中找到该表的IAM页链——也就是全部数据页集合这就是对一个没有建立索引的数据表进行数据查找的方式,是不是很没效率?对于没有索引的表,对于一堆这样的纪录,SQLS也只能这样做,而且更没劲的是,即使在第一行就找到了被查询的纪录,SQLS仍旧要从头到尾的将表扫描一次这种查询称为遍历,又叫表扫描〃可见没有建立索引的数据表照样可以运行,不过这种方法对于小规模的表来说没有什么太大的问题,但要查询海量的数据效率就太低了
(二)SQLS怎样访问建立了非聚集索引的数据表如前所述,非聚集索引可以建多个,具有B树结构,其叶级节点不包含数据页只包含索引行假定一个表中只有非聚集索引,则每个索引行包含了非聚集索引键值以及行定位符(ROWIRID)他们指向具有该键值的数据行每一个RID由文件ID、页编号和在页中行的编号组成当INDID的值在2・250之间时,意味着表中存在非聚集索引页此时,SQLS调用ROOT字段的值指向非聚集索引B树的ROOT在其中查找与被查询最相近的值,依据这个值找到在非叶级节点中的页号,然后顺藤摸瓜,在叶级节点相应的页面中找到该值的RID最终依据这个RID在Heap中定位所在的页和行并返回到查询端例如假定在Lastname上建立了非聚集索引则执行Select*FromMemberWhereLastname=Ota时,查询过程是
①SQLS查询INDID值为2;
②马上从根动身,在非叶级节点中定位最接近Ota的值Martin”并查到其位于叶级页面的第61页;
③仅在叶级页面的第61页的Martin下搜寻Ota的RID其RID显示为N:706:4表示Lastname字段中名为Ota的纪录位于堆的第707页的第4行,N表示文件的ID值,与数据无关;
④依据上述信息,SQLS立马在堆的第707页第4行将该纪录揪出来并显示于前台(客户端X视表的数据量大小,整个查询过程费时从百分之几辜秒到数辜秒不等在谈到索引基本概念的时候,我们就提到了这种方式图书馆的前台有很多索引卡片柜,里面分了若干的类别,诸如依据书名笔画或拼音挨次、作者笔画或拼音挨次等等,但不同之处有二
①索引卡片上纪录了每本书摆放的具体位置一位于某柜某架的第几本一而不是“特别编号;
②书脊上并没有那个“特别编号管理员在索引柜中查到所需图书的具体位置(RID)后,依据RID直接在书库中的具体位置将书提出来(可以想象成数是杂乱无章的摆放)明显,这种查询方式效率很高,但资源占用极大,由于书库中书的位置随时在发生变化,必定要求管理员花费额外的精力和时间随时做好索引更新
(三)SQLS怎样访问建立了聚集索引的数据表在聚集索引中,数据所在的数据页是叶级,索引数据所在的索引页是非叶级查询原理和上述对非聚集索引的查询相像,但由于纪录是依据聚集索引中索引键值进行排序,换句话说,聚集索引的索引键值也就是具体的数据页这就好比书库中的书就是依据书名的拼音在排序,而且也只依据这一种排序方式建立相应的索引卡片于是查询起来要比上述只建立非聚集索引的方式要简洁得多仍以上面的查询为例假定在Lastname字段上建立了聚集索引,则执行Select*FromMemberWhereLastname=Ota时查询过程是
①SQLS查询INDID值为1这是在系统中只建立了聚集索引的标志;
②马上从根动身,在非叶级节点中定位最接近Ota的值Martin,并查到其位于叶级页面的第120页;
③在位于叶级页面第120页的Martin下搜寻到Ota条目,而这一条目已是数据纪录本身;
④将该纪录返回客户端这一次的效率比其次种方法更高,以致于看起来更美,然而它最大的优点也恰好是它最大的缺点一由于同一张表中同时只能依据一种挨次排列,所以在任何一种数据表中的聚集索引只能建立一个;并且建立聚集索引需要至少相当于源表120%的附加空间,以存放源表的副本和索引中间页!莫非鱼和熊掌就不能兼顾了吗?方法是有的
(四)SQLS怎样访问既有聚集索引、又有非聚集索引的数据表假如我们在建立非聚集索引之前先建立了聚集索引的话,那么非聚集索引就可以使用聚集索引的关键字进行检索就像在图书馆中,前台卡片柜中的可以有不同类别的图书索引卡,然而每张卡片上都载明白那个特别编号一并不是书籍存放的具体位置这样在最大程度上既照看了数据检索的快捷性,又使索引的日常维护变得更加可行,这是。
个人认证
优秀文档
获得点赞 0