资料下载网
首页 计算机 考试教辅
SQL Server 2005编程入门经典 pdf电子书免费下载,百度云
首页 > 计算机 > 数据库技术 > SQL Server 2005编程入门经典 pdf电子书免费下载,百度云

《SQL Server 2005编程入门经典》pdf电子书免费下载


下载方式一:

百度网盘下载地址:https://pan.baidu.com/s/1o3xv3TkSAFDq-XH48hQqjQ
百度网盘密码:1111

下载方式二:

http://ziliaoshare.cn/Download/ae_123636_pd_SQLServer2005BCRMJD.zip

 


SQL Server 2005编程入门经典

作者:empty

页数:96

出版社:empty

《SQL Server 2005编程入门经典》介绍

索引是数据库设计和系统维护的关键部分。它们为SQLServer(以及就此而言的任何其他的数据库系统)提供了查询数据和获得数据物理位置的快捷方式的其他方法。添加正确的索引能够减少查询之外操作所占的大量时间。遗憾的是,许多设计很差的索引实际上会增加查询运行所花费的时间。毫无疑问, 索引趋向于成为一种SQLServer提供的最令人误解的对象,因此索引也趋向于成为一种最容易管理不当的对象。本章将从开发者和管理者的角度学习索引, 但是为了理解索引, 也需要理解在SQLServer中是如何存储数据的。因此, 本章将首先介绍SQLServer的数据存储机制。9.1 SQLServer存储在SQLServer中的数据可以看作是存在于一种层次结构中的对象。这种层次结构相当简单。在这种层次结构中的一些对象是您将要直接处理的,并且将因此很容易地理解它们。少数其他的一些对象存在于隐蔽处,虽然在某些情况下可以直接处理它们,但是在通常情况下是不可以的。下面将逐个介绍。9.1.1数据库数据库比较容易。我听见人们说:“数据库,我知道的.”是的,您可能知道,但是因为它是存储定义的最高层次(对于给定的服务器),所以我在这里将它作为独特的实体指出。尽管您不能明确地创建一个数据库层次的锁,但这是可以建立锁的最高层次,提示:锁既是系统使用的保持标记, 也是放置标记。当您使用SQLServer进行开发时——或者就此而言的其他数据库——您将发现理解和管理锁对于系统而言是绝对关键的。将在第14章中详尽地介绍锁, 但是首先介绍在查看存储时顺便讨论的SQLServer中对象的可锁定性。9.1.2盘区盘区是存儲的基本单元,这些存储用米为表和索引分配空间。它由8个连续的64K数据页面组成。在盘区(而不是实际使用空间)基础上分配空间的概念,对于习惯于操作系统存储原理的人们而言可能稍微难于理解。关于盘区的要点包括:一日盘区已满,那么下一个记录将要占据的不是记录的大小,而是整个新盘通过预先分配空间, SQLServer节省了为每个记录分配新空间的时间,数据:数据页面是自解释的——它们是在表中的实际数据,例外情况是任何索引:索引页面也是相当直观的——它们既拥有非群集索引的非叶层次的页区的大小。许多SQLServer的新手在空间估计上犯错误, 一部分原因是由于一次分配一个盘区而不是一个记录。只是因为添加了过多的行以适合当前分配的分区,所以可能看起来占用整个盘区是一种浪费,但是这种方法浪费的空间数量一般不是非常多。尽管如此,它可以累加——特别在片段较多的环境中——所以它是您应当紧记的确切内容。占据所有空间的好消息是SQLServer跳过了一些分配时间的系统开销。不需要担心每次写入一行时的分配问题, SQLServer仅仅当需要新的盘区时才处理额外的空间分配。提示:不要将盘区占据的空间和数据库占有的空间相互混淆。不管将哪些空间分配给数据库,将看到从磁盘驱动器的可用空间上消失的内容。盘区仅仅是事物在由数据库保存的整个空间内按照顺序分配的方式。9.1.3页面在数据库中和盘区很相似的内容是分配单元,页面是在特定盘区内的分配单元。每一个盘区包含8个页面。页面是在到达实际数据行之前所达到的最后一个层次。尽管每一个盘区中的页面数目是固定的,但是每一个页面中的行数目不是固定的——这完全取决于行的大小,而行的大小是可以变化的。可以把页面认为是既用于表又用于索引行数据的容器。不允许在页面之间进行拆分。有许多种不同的页面类型。对于本书的目的而言,所关心的类型包括:页面拆分没有以text in row选项或者varchar(max) 定义的BLOB数据。面,也拥有叶层次的页面(将要在本章后面研究这些内容),而且也拥有群集索引的非叶层次的页面,通过本章的继续叙述,将更加了解这些索引类型,当页而已满时,可对其进行拆分。这意味着多个新的页面被分配——它也意味着来自现有页面上的将近一半的数据被移动到新的页面上。当使用群集索引时,对于这个过程而言是个例外。如果有一个群集索引,而且下一个插入的行将在物理上作为表中最后的记录定位,那么创建新的页面,并且将新的行添加到这个新的页面,而不需要重新定位任何现有的数据。当研究索引时,将要看到更多的页面拆分。9.1.4行您将要看到许多关于“行层次锁定”的内容,所以在听到这个术语时不应感到惊讶。行可以最大达到8KB。除了8060字符的限制,还有最大1024列的限制.实际上,当达到8060字符限制之前,您将会发现到达用完允许的最多列的情况是不常见的。1024提供了8个字节的平均列宽度。对于大多数使用情况,您将会很容易超出这个限制.这方面的例外情况可能是在度量和统计信息中——其中有很多的不同内容,这些是您正在存储的数值的例子9.2理解索引Webster的字典定义索引如下:

提示:通常以一些指定数据(如作者、主题或者关键字)的字母顺序排列的列表(作为著作的主要部分的目录信息或者引用)。我将要在数据库上下文中使用较为简单的方法,并且将它介绍为一种快速到达数据的潜在方法。尽管如此, Webster的定义不是太坏——甚至对于特定的目的而言。也许在Webster的定义中指出的关键内容是单词“通常”。“字母顺序”的定义根据许多规则而变化。例如, 在SQLServer中, 有许多不同的可用整理选项。其中一些选项如下:二进制:根据字符的数字表示排序(例如, 以ASCII码的形式, 用数字32表示字典顺序:这种排序方式与期望在字典中看到的排序方式一样,但是具有变空格,用68表示字母“D ,但是用100表示字母“d )。因为每个内容都是数字,所以这是最快的选择—遗憾的是, 它完全不是人们思考的方式, 并且在WHERE子句中进行比较时,使用这种选项会带来严重的负面影响。通——您可以设置许多不同的额外选项来决定是否区分大小写、音调和字符集。如果告诉SQL Scr ver注意大小写, 那么“A 将和“a 不相等, 理解这一点相当简单。同样地, 如果告诉SQLServer不区分大小写, 那么“A”将和“a 相等。当您添加音调区分时,事情变得使人困惑——也就是说, SQLServer注意可区别的标记, 因此“a 和“a 是不同的,和“a 也不同,以下情况会使许多人变得甚至更加困惑:整理顺序如何不仅影响数据的等式,而且影响排序的顺序(从而影响在索引中存储它的方式)。通过示例的方法,查看在表9-1中的一些整理选项的等式,以及它们对排序顺序和等式信息的影响。见表9-1.

字典顺序、区分大小写、区A=am a mama=A=A,a,a,a,a,A.a,分音调、大写字母优先i-A-aA.a字典顺序、区分大小写A_aA_a,A_a,A.a,a,a.a,A.a,这里的要点在于:在索引中所发生的情况取决于为数据建立的整理信息。可以在数据库或者列的层次上设置整理,所以在控制级别上有相当好的粒度。如果假定服务器是区分大小写的,那么需要确保系统文件处理这一点,或者有更好的关于技术支持电话的计划一特别是如果您正在美国之外进行销售。设想您是独立的软件供应商(IS V) , 并且您将产品销售给在现有的服务器上安装它的顾客(对于顾客而言,这似乎是完全合理的事情),但是现有的服务器碰巧是已经设置为区分大小写的老式服务器。您将会接收到米自非常不满意的顾客的电话,要求相关的技术支持。注意:一旦设置了整理顺序,改变它是非常重要的(但是可能的),所以在设置之前确定需要的整理顺序。9.2.1平衡树(B-树)平衡树或B-Trec的概念当然不是伴随着SQLServer一起创建的, 实际上, 在数据库内外有非常多的索引系统使用平衡树。平衡树仅仅试图提供一种一致的并且相对低成本的方法,该方法用于查找特定的信息块。名称中的“平衡”是自描述的——平衡树是自平衡的(只有很少的例外情况),这意味着每次树的分支都有接近一半的数据在一边,而另一半数据在另一边,名称中的“树”在这一点上可能也是非常明显的——当您绘制该结构,然后完全颠倒它时,该结构具有树的一般形式,因此称为树。平衡树在根节点处开始(另一个类似于树的方面,但不是最后的方面)。如果有少量的数据,这个根节点能够直接指向数据的实际位置。在这种情况下,您将最终获得看起来如图9-1所示的结构。所以,在根节点开始并浏览记录,真到找到最后一页,该页开始于小于正在查找值的数值。然后获得指向该节点的一个指针,并且浏览它,直到找到想要的行。然而,在大多数情况下,有太多通过根节点引用的数据,所以根节点指向中间的节点―或者称为非叶层次的节点。非叶层次的节点是在根节点和告诉您数据物理存储位置的节点之间的节点。非叶层次的节点可以指向其他非叶层次的节点,或者指向叶层次的节点(最后一个类似于树的引用)。叶层次的节点是在其中获得实际物理数据的引用的节点。树叶是定位实际树的路线的末端,与此类似,在叶层次上所到达的节点是用于索引的行的末端――从这里,可以直接到达在其上有数据的实际数据节点。从图9-2中可以看出,开始于根节点,然后移动到以如下最高值开始的节点:等于或者略小于所寻找的值,并且也是在下一个层次上的最高值。然后重复这个过程—寻找具有等于或者小于所寻找值的最高起始值的节点。继续沿着树一层一层往下,直到到达叶层次一一从叶节点中知道数据的物理位置,并且可以很快地定位它。

页面拆分——简介所有这些在等式的阅读方面工作良好——它是有点需要技巧的插入。回顾一下,在B-树中的B代表平衡(Balanced) 。您也可以回顾一下, 前面提到每次当您遇到树中的分支时,因为大约一半的数据是在任意一边的,所以B-树是平衡的。因为添加新数据到树上的方法一般可避免它们的不平衡,所以B-树有时候被认为是自平衡的。当添加数据到树上时, 节点将要最终填满, 并且将需要拆分。因为在SQLServer中, 一个节点等于一个页面——这称为页面拆分,在图9-3中解释.提示:当页面拆分发生时,数据自动地四处移动以保持内容上的平衡。数据的前半部分保留在旧的页面上,而数据的剩余部分添加到新的页面——这样您有大约对半的拆分,并且您的树保持平衡,如果考虑这个拆分过程,将认识到它在拆分时增加了大量系统开销。没有插入一页,而是:但是,系统开销没有在此处停止。因为在一个树的排列中,有级联动作内容的可能性。创建新的页面时(因为拆分的缘故),需要在父节点中建立另一个记录项。在父节点内的这个记录项在该层次也具有导致页面拆分的潜在可能,而且整个过程再次开始。实际上,这种可能性扩展到所有的方面,而且甚至能影响根节点。如果根节点拆分,那么您实际上最终会创建两个额外的页面。只能有一个根节点,所以正常是根节点的页面被拆分成两个页面,而且成为树的新的中间层次。然后创建了全新的根节点,并且将有两个记录项(一个到达旧的根节点,另一个到达拆分的页面)。不必说,页面拆分对系统性能产生非常消极的影响,并且通过在服务器上看起来只是暂停儿秒(此时页面被拆分并且重写)的过程的行为来表现。在完成本章之前,将讨论页面拆分的预防。提示:虽然在叶层次上的页面拆分是生活中普通的事实,但是在中间节点上的页面拆分却很少发生。当您的表增长时,索引的每一层将经历页面拆分,但是,因为中间节点对于下一个较低层次的节点上的一些记录项只有一个记录项,所以向树的上层移动时,页面拆分的数量变得越来越少。尽管如此,对于一个发生在页层次上的拆分,在下一个最低层次上一定已经有一个拆分——这意味着树上的页面拆分在本质上是累积的(而且严重影响性能)。虽然SQLServer具有许多不同类型的索引(后面将简单地讨论这一点) , 但是所有这些索引以一些方式或者其他方法利用这种平衡树方法。实际上,由于平衡树的灵活的特性,所有的索引在结构上非常类似。尽管如此,将看到实际上有一些重要的区别,并且这些区别能对系统的性能产生影响。提示:对于SQLServer索引而言, 树的节点以页面的形式出现, 但是您实际上可以将根节点、非叶层次、叶层次以及树结构的概念应用于不同于SQLServer的其他方面, 或者甚至是应用于数据库。9.2.2 SQLServer中数据的访问方式就广义上而言, SQLServer检索所请求数据的方法只有两种:SQLServer将使用何种方法来执行特定查询将取决于可用的索引、正在请求的列、正在使用的连接以及表的大小,1.表扫描的使用方法表扫描是相当直观的过程。当执行表扫描时, SQLServer在表的物理起点处开始, 浏览表中的每一行。当发现和您的查询标准匹配的行时,就在结果集中包含它们。您可能听过有关表扫描的不好的方面,一般而言,这些情况是真实的。但是,表扫描在创建新的页面将行从现有的页面移动到新的页面上添加新行到一个页面上在父节点内添加另一个记录项使用表扫描使用索引

一些实例中实际上是最快的访问方法,一般来说,当从相当小的表中检索数据时,使用表扫描就非常好。在这种情况中,准确的大小将根据表的宽度和查询的特定性质而有很大变化。提示:查看是否可以发现如下方面的原因:在查询的WHERE子句中使用EXISTS在一定程度上提供了适合问题的性能方面。当您使用EXISTS运算符时, 只要找到和标准匹配的记录,SQLServer就会立即停止。如果您有包含一百万条记录的表, 而且在第三个记录中找到了匹配的记录, 那么EXISTS选项的使用将节省阅读999, 997条记录的时间!NOT EXISTS以基本相同的方式工作。2.索引的使用方法当SQLServer决定使用索引时, 该过程实际上与表扫描的工作方式相类似, 但是具有一些捷径。在查询优化过程期间,优化器查看所有可用的索引并且选择最好的一个(这主要基于在连接和WHERE子句中所指定的信息, 并且结合SQLServer在索引组成上保持的统计信息) 。一旦选择了索引, SQLServer将树结构定位到和您的标准匹配的数据位置, 并且再次只提取它所需要的数据。区别在于,因为数据是排序的,所以查询引擎知道它何时到达正在查找的当前范围的结尾。然后它可以结束查询,或者根据需要移动到下一个数据范围。如果考虑迄今己经研究的查询主题(特别是第7章) , 可以注意到一些与EXISTS选项的工作方式显著的类似之处。EXISTS关键字允许查询在找到一个匹配时立刻停止运行。因为查找数据的过程可以以类似的方式工作,使用索引的性能收益是类似的或者甚至更好一也就是说,服务器能够知道何时没有相关的内容,并且能在该处停止它。尽管如此,甚至更好的情况是,通过使用索引,不需要将自己限制在布尔逻辑的情况中。可以将这种相同的概念应用到范围的开始和结束——能够收集一定范围内的数据,这在本质上具有与使用索引提供给查找数据同样的优点。此外, 可以在数据中执行非常快速的查询(称为SEEK) , 而不是在整个表中查找。提示:不要因为前面比较索引与EXISTS运算符所做的事情就认为索引可完全代替EXISTS运算符(或者相反)。这两者不是相互排斥的:它们可以放在一起使用,并且经常放在一起使用。我在这里同时提到它们,仅仅是因为它们在如下方面具有相似性:能够告诉其工作何时完成,以及在到达表的物理结尾之前退出。3.索引类型和索引导航尽管名义上在SQLServer中有两种索引(群集索引和非群集索引) , 但是实际上, 就内部而言,有3种不同的类型:物理数据的存储方式在群集索引和非群集索引之间变化。SQLServer遍历平衡树以到达末端数据的方式在所有3种类型之间变化。所有的SQLServer索引具有叶层次和非叶层次的页面。正如讨论平衡树时所提到的那样,叶层次是保持标识记录的“键”的层次,非叶层次的页面是叶层次的引导者。索引在群集表上(如果表有群集索引)或者堆上(用于没有群集索引的表)创建。4.群集表群集表是在其上具有群集索引的任意表。后面将详细讨论群集索引,但是它们对于表而言意味着在物理上以指定顺序存储的数据。通过使用群集键唯一地标识独立的行——群集键即定义群集索引的列。引不是唯一索引, 那么群集索引如何用于唯一地识别一行?答案隐藏在其中——SQLServer迫使任何群集索引为唯一的—即使您没有以这样的方式定义。幸运的是, 以一种不改变使用索引方法的方式来完成这一点。如果您希望的话,仍然可以插入重复的行,但是SQLServer将在内部添加一个后缀到键上, 以保证行具有唯一的标识符。堆是在其上没有群集索引的任意表。在这种情况下,基于行的盘区、页面以及行偏移(从页面的顶部放置) 的组合创建唯一的标识符, 或者称为行ID(RID) , 如果没有有用的群集键(没有群集索引) , 那么RID是唯一必要的内容。群集索引对于任意给定的表而言是唯一的——可以在一个表中只有一个群集索引。不一定要有群集索引,但是由于在索引类型时将变得明显的多种原因,您将会发现它是作为第一使群集索引特殊化的方面是,群集索引的叶层次是实际的数据——也就是说,数据被重新排序,从而以和索引排序标准声明的相同物理顺序存储。这意味着,一旦到达索引的叶层次,就完成了工作——即到达了数据。任何新的记录根据它的正确物理顺序插入到群集索引。新页面的创建方法根据需要在何处插入记录而变化。在新记录需要插入到索引结构中间的情况下,会发生正常的页面拆分。来自旧页而的后一半记录被移动到新的页面,并且在适当的时候,新的记录插入到新的页面或旧的页面。在新的记录逻辑上位于索引结构末端的情况中,创建一个新的页面,但是只有新的记录群集索引非群集索引——它包含:·堆上的非群集索引·群集索引上的非群集索引提示:这应当想起这样的问题:5.堆6.群集索引个索引的一种最经常选择的类型。添加到新的页面,如图9-4所示。“如果群集索引不是唯一的,那将怎样?”也就是说,如果索

7.导航树正如前而已经暗示的, 在SQLServer中甚至索引也存储在平衡树中。在理论上, 平衡树在作为树分支的每一个可能方向上总是具有一半的剩余信息。查看对于群集索引而言平衡树的可视化效果(图9-5)。正如所看到的那样,它看起来和本章前面讨论的较为一般的平衡树是基本相同的。在这种情况下,正在进行对于数字158~400的范围查询(群集索引特别擅长的事情)。需要做的工作是导航到第一个记录,并且包含在该页面上的所有剩余的记录。因为通过来自于节点1层次向上的信息,可以知道也需要来自于一些其他页面的数据,所以知道需要该页面的剩余部分。因为这是有序的列表,所以可以确信它是连续的——这意味着如果下一个页面有应当包含的记录,这个页面的剩余部分必须包含。可以仅仅从那些不需要验证的页面上提取数据。首先导航到根节点。SQLServer能基于在Sys indexes系统表中保持的记录项定位根节点。注意:数据库中的每一个索引在sys indexes里有一个记录项。系统表是数据库的一部分(与在主数据库中的情况相对),而且为数据库中的所有索引和它们基于的列存储位置信息。通过查找作为根节点的页面,能指出下一个需要检查的页面是什么(正如在这里绘制的第2个层次上的第2个页面)。然后继续这个过程。每一步沿着树向下,到达越来越小的数据子集。最终,将到达索引的叶层次。在群集索引的情况下,到达索引的叶层次意味着也到达了期望的行和期望的数据。注意:我不能过多地强调如下区别的重要性:使用群集索引,当您已经完全定位索引时,您己经完全定位到您的数据。当查看非群集索引时,这如何产生大多数的性能区别将真正显示出来——特别地,当非群集索引建立在群集索引之上时,8.堆上的非群集索引在堆上的非群集索引和群集索引在大多数方面以类似的方式工作。尽管如此,它们具有一些显著的差别:叶层次不是数据——相反,它是这样一个层次,在这个层次上能够得到指向该数据的指针。该指针以RID的形式出现, 如同在本章前面描述的那样, 这种RID组成了特定行的盘区、页面以及行偏移,由索引指向该行。即使叶层次不是实际的数据(相反,它具有RID) , 仅仅比使用群集索引具有一个更多的步骤——因为RID具有行的位置的全部信息,所以可以直接到达数据。然而,不要将“一个更多的步骤”误解为只有少量的开销区别,并且在堆上的非群集索引将和群集索引几乎一样快地运行。使用群集索引,数据在物理上是按照索引的顺序排列的。这意味着,对于一定范围的数据,当您找到在其上具有您的数据开始的行时,那么有其他行在带有它的页面上的好机会(也就是说,因为它们存储在一起,已经在物理上几乎到达下一个记录)。使用堆,数据以不同于通过索引的其他方法连接在一起。从物理上的观点看,绝对没有任意种类的排序。这意味着,从物理读的观点看,您的系统可能不得不从整个文件中检索记录。实际上,很可能最终多次从同样的页面中取出数据——因为在数据之间没有连接, 所以SQLServer没有方法知道它将需要回到该物理位置。使用群集索引, 它知道这是物理上的排序,因此能在仅仅访问一次页面时就完全获得数据。提示:仅仅是为了公平对待堆上的非群集索引和群集索引,非常奇怪的事情是任何已经读取一次的页面将仍然在内存缓存中,而且同样将非常快地被检索。此外,它添加了一些额外的逻辑操作到检索数据中。图9-6说明了与利用群集索引时同样的查询,只是这次使用在堆上的非群集索引方式。通过大多数索引导航,事情确切地按照以前的方式工作。以相同的根节点开始,并且遍历树,处理越来越聚焦的页面,直到到达索引的叶层次。这是遇到区别的地方。以群集索引的方式,能够正好在这里停止,而以非群集索引的方式,则需要做更多的工作。如果非群集索引是在堆上,那么只要再进入一个层次。获得来自叶层次页面的行的ID,并且定位到它——直到此处才可以直接获得实际的数据。

9.在群集表上的非群集索引使用群集表上的非群集索引,这种类似性继续存在——但是区别也一样继续存在。和堆上的非群集索引一样,索引的非叶层次看起来几乎与它为群集索引所做的一样。区别直到到达叶层次才出现。提示:在叶层次上,与使用其他两种索引结构所看到的内容有相当明显的区别——也有另一个索引来检查这一点。使用群集索引,当到达叶层次时,可以找到实际的数据。使用在堆上的非群集索引,不能找到实际的数据,但是可以找到能够直接获得数据的标识符(仅仪远了一步)。使用在群集表上的非群集索引,可以找到群集键。也就是说,找到足够的信息以继续并利用群集索引。最终获得类似于图9-7中的内容。最终获得的是两种完全不同的查找。在来自图9-7的示例中,开始于一个范围搜索——在索引中执行一次单独的查找,并且能够浏览非群集索引以找到满足标准(LIKE T%) 的连续数据列。在这种查找中能够直接到达索引中的特定位置, 称为定位(seck) 。然后开始第二个查找——使用群集索引的查找。第二种查找非常迅速;问题在于如下事实, 即它必须发生多次。可以看到, SQLServer从第一个索引查找里检索列表(所有名字以“T*开始的列表),但是该列表在逻辑上不能和以任意连续方式的群集键相匹配——每一个记录需要单独地查找,如图9-8所示。不必说,这种多个查找的情况比一开始仅能使用群集索引引入了更多的系统开销。第一个索引查找——通过非群集索引的方法—将需要非常少的逻辑读。例如,如果有一个每行1000字节的表,而且执行了类似于图9-6的查找(也就是说,将要返回5行或者6行的内容);它将仅以8到10个逻辑读的顺序获得来自于非群集索引的信息。然而,这仅使得我尽可能快地在群集索引中查找行。每个这些查找将花费3到4个逻辑读,或者15到24个额外的读取,最初看起来,这可能并不是大问题,但是以这样的方式查看它,逻辑读从最小为3到最大为24—在需要完成的工作数量上以800%增长,现在扩展这种想法到一些事情,其中来自于非群集索引的数值的幅度不仅是5或6行,而是5000或者6000行,或者500000或600000行——将有巨大的影响,提示:不要让与群集索引对比的额外开销惊吓到您——这些内容不意味着让您远离使用索引,而是帮助您认识到从读的观点看,非群集索引将不会和群集索引一样有效(在一些实例中,它可能是在插入时实际上更好的选择)。任意种类的索引经常(有一些例外)是执行查找的最快方法。将在本章后面的内容中解释使用何种索引以及为什么使用这种索引。图

9.3创建、改变和删除索引这些操作和它们在其他对象(例如表)上所做的工作完全一样。查看每一个操作,首先从CREATE开始。可以以两种方式创建索引:因为这些方式具有自己可以做什么和不能做什么的特性,所以分别查看这两种方式。9.3.1 CREATE INDEX语句CREATE INDEX语句准确地执行应该完成的工作——它在基于声明列的指定表或视图上创建索引。创建索引的语法在一定程度上进行了扩展,并且引入一些到日前为止还没有真正谈论的项:CREATE[UNIQUE] [CLUSTERED|NON CLUSTERED]INDEX index name>ON table or view name>( columnname>[ASC] DESC] [....n] )INCLUDE( columnname>[....n] )[WITH[PAD_INDEX={ON|OFF 1][LJ FILL FACTOR- ill factor>][[] IGNORE_DUP_KEY-1ON|OFF I][[] DROP_EXISTING={ON|OFF I][[] STATISTICS_NO RECOMPUTE={ON|OFF) ][[J SORT_IN_TEMPDB={ON|OFF 11[[J ONLINE=(ON|OFF)[[.] ALLOW_ROW_LOCKS-(ON|OFF)[[] ALLOW_PAGE LOCKS={ON|OFF[[] MAX DOP= maximum degree of parallelism>[ON( ile group>| partition.scheme name>|DEFAULT】]提示:对于这些选项中的许多而言,有传统的可用语法,因此可能会看到使用这种语法以支持先前版本的SQLServer。但是, 不赞成使用该语法, 并且将在某些情况下删除它——我非常推荐您尽可能使用较新的语法。注意:对于创建XML索引而言, 有一个类似的但完全不同的语法。在本节的最后将单独地处理它。宽松地说, 这种语句遵循前面己经经常看到的相同CREATE objecttype> objectname语法(而且将要更多地看到这种语法)。主要问题是有一些在其他地方还没有看到过的插入参数。正如在下一章中将要看到的关于视图的内容, 必须在CREATE语句上添加额外的子句以处理如下事实:索引实际上不是单独的对象。它必须带有表或者视图,并且需要声明该表,列是“ON”.在ON table or view name>( columnname>) 子句之后, 每个内容都是可选择的。您可以混合以及匹配这些选项。它们中的大多数很少使用, 但是一些选项(例如FILL FACTOR) 可通过显式的CREATE INDEX命令当创建约束时作为隐含的对象

以对系统性能和行为产生明显的影响,所以逐个查看它们。1.ASC/DESC这两个选项允许您在索引的升序排列和降序排列之间进行选择。默认选项为ASC, 它是升序排列。可能会产生如下的疑问,为什么升序比降序更为要紧——可以看到,如果需要相反的排列顺序, SQLServer可能仅仅是反向查看索引。但是, 生活不是总如此简单。如果您正在处理仅仅一列,或者如果您的排序对于所有列总是相同的,那么以相反的顺序查看索引可工作良好但是如果您需要在索引中混合排序顺序,这会发生什么?也就是说,如果您需要一列按照升序排序,但是其他列按照降序排列,这该如何处理?因为索引的列存储在一起,所以颠倒对于查看索引中一列的方法将也颠倒其他列的查看顺序。如果您明确地声明某一列是升序的,而另一列是降序的,那么您将正确地在物理数据中颠倒第二列——突然没有任何理由改变您访问数据的方法。作为快速示例,设想一个报表,在其中需要将您的雇员列表按照雇佣日期排序,从最近雇佣的开始(降序) , 但是也想按照他们的姓(升序) 排列。在早期的版本中, SQLServer将不得不执行两个操作—一个用于第一列,另一个用于第二列,通过允许控制数据的物理排列顺序,通过组合列的方法获得灵活性。一般而言,不需要干涉这一点(再一次声明,记住向后兼容性)。一些可能的例外是:2.INCLUDE这是SQLServer 2005增加的非常良好的新内容。它的目的是为称为覆盖查询(coveredqueries) 的内容提供更好的支持。相对于将列放置在ON列表上, 当INCLUDE列时, SQLServer仅仅在索引的叶层次上添加它们.因为在索引叶层次上的每一行对应于一个数据行,所以所正在做的事情在本质上不仅包含在索引叶层次上的原始数据。如果您考虑到这一点, 或许会猜测INCLUDE实际上仅仅应用于非群集索引(群集索引已经是在叶层次上的数据, 所以无法应用INCLUDE) 。为什么这一点要紧呢?在本书后面进一步讨论时,一旦SQLServer有了它实际上需要的内容,它就停止工作。所以,如果在遍历索引时能找到需要的所有数据,而没有继续到达实际的数据行,那么它将不会干扰到达数据行(关键是什么?).通过在索引中包含特定的列,您可以“覆盖”查询,该查询利用在叶层次上的特定索引,并且保存与使用该索引的指针到达数据页面相关的I/O。提示:注意不要滥用该选项!当INCLUDE列时, 您正在扩大索引页面的叶层次的大小, 这意味着更少的行将适合每一个页面,因此需要更多的I/O来查看相同数量的行。结果可能是,您加速一个查询的努力可能减慢其他的查询。考虑对于系统的所有部分的影响,而不是仅仅考虑此时正在使用的特定的查询。3.WITHWITH非常简单—它只是告诉SQLServer实际上将要提供接下来的一个或者多个选项。4.PAD INDEX在语法列表中, 该选项第一个出现——但是当您理解PAD INDEX所做的工作时, 该选项看起来将非常奇怪。简而言之,当第一次创建索引时,该选项只决定了索引中非页层次页面的填充程度(作为百分比) 。因为将使用后面的FILL T ACTOR选项中指定的任何百分比,所以在PAD INDEX上没有声明百分比。设置不带有FILL FACTOR选项的PAD_INDEX=ON将是没有意义的(这就是它第一次出现时看起来非常奇怪的原因)。5.FILL FACTOR当SQLServer第一次创建索引时, 默认情况下尽可能将其填满, 减去两个记录。您可以将FILL T ACTOR设置为在1和100之间的任意值。一旦索引构造是完整的, 这个数字将代表填充您的页面的百分比。但是,牢牢记住在进行页面拆分时,您的数据将仍然在两页之间对半分布——您不能在正在进行的基础上控制填充百分比,除了有规则地重新构建索引(您应当做的事情——第20章中介绍了为这一点建立维护进度表)。当需要调整页面密度的时候, 使用FILL T ACTOR.按如下方式考虑:如果没有提供值, 那么SQLServer将填充您的页面, 其中有两行不满, 并且每页最少一行(例如,如果您的行是8000个字符宽,那么可能只适合每页一行——因此留下两行短的内容将不起作用)。6.IGNORED UP_KEYIGNORED UP_KEY选项是仅仅完成绕开系统的方法。简而言之, 它造成UNIQUE限制具有与其他情况下稍微不同的操作。正常情况下,唯一的限制(或唯一的索引)不允许任何种类的任何复制—如果事务尝试基于定义为唯一的列创建重复内容,那么事务将回滚并且被拒绝。然而,一旦您设置了IGNORED UP KEY选项, 您将得到混合行为的内容。仍然接收错误消息, 但是错误将仅仅是一种警告——记录仍然没有被插入。不会针对该事务提交回滚(错误是警告错误,而不是关键错误),但是复制的行将被拒绝。为什么要做这件事呢?它是存储唯一值的方法,而不是干扰尝试插入重复内容的事务。对于任何正在插入将是重复内容的过程,复制行完全没有问题(没有来自于它的逻辑错误).相反,该过程可能具有更为直接的态度:“只要知道那里有类似的行,我就会非常高兴―如果指定DROP_EXISTING选项, 那么具有所讨论名称的任何现有索引将在构造新索需要混合跨越多个列的升序和降序。向后兼容性不是一个问题。如果是OLTP系统, 那么需要较低的FILL FACTOR。如果是OLAP或者其他非常稳定的(就改变而言——非常少的增加和删除) 系统,如果有一个具有中等事务率和根据它的许多报表类型查询的内容,那么您可一“记录仍然没有被插入”——是从IGNORE_DUP_KEY观点看的关键概念。那么需要尽可能高的FILL FACTOR.能需要中等水平的FILL FACTOR(不是太低, 也不是太高) ,最后一行一―我不关心它是否是我尝试插入的特定行”。7.DROP EXISTING

引之前被删除。当和群集索引一起使用该选项时,这个选项比简单删除并重新创建现有的索引更加有效。如果重新构建现有索引的确切匹配, 那么SQLServer知道它不需要涉及非群集索引,而显式的删除和创建将涉及重新构建所有非群集索引两次,从而包括不同的行位置。如果使用DROP EXISTING改变索引的结构, 那么NCI只被重新构建一次, 而不是两次。此外,不能简单地册除和重新创建由约束所创建的索引,例如,用于实现特定的填充因数。DROP EXISTING是针对这一点的工作区,8.STATISTICS_NO RECOMPUTE默认情况下, SQLServer试图自动化在表和索引上更新统计的过程。通过选择STATISTICS NO RECOMPUTE选项, 表示将对更新统计负责任。为了关闭这个选项, 需要执行UPDATE STATISTICS命令, 而不是使用NO RECOMPUTE选项,这里强烈推荐反对使用这个选项。原因何在?索引上的统计是查询优化器用于指出索引对于给定查询如何有帮助的内容,当表中的数据在容量上来回变化以及列中的特定值改变时,索引上的统计会经常变化。当将这两个事实组合在一起时,应当能够看到没有更新统计意味着查询优化器将基于数据内部的日期信息运行查询。打开自动统计特性意味着统计将有规律地更新(多长时间更新取决于对表的更新的性质和频繁程度)。相反,关闭自动统计意味着您将是过时的, 或者将需要建立进度表以手动地执行UPDATE STATISTICS命令。9.SORT_IN_TEMPDB只有在tcm pdb存储在与数据库(该数据库将包含新的索引) 物理上分离的驱动器上时, 该选项才有意义。该选项在很大程度上是管理功能,所以不会过多介绍这个主题,而只是简要概述它是什么以及为什么它只有在tempdb位于独立的物理设备上时才有意义。当SQLServer建立索引时, 它必须执行多个读操作以考虑各种索引构造步骤:(1)遍历所有的数据,构建对应于实际数据每一个行的叶行。类似于实际的数据和最后的索引,这些内容进入用于中间存储的页面。这些中间页面不是最终的索引页面,而是在每次排序缓冲器已满时临时存储内容的保存位置。(2)通过这些中间页面执行单独的运行,以将它们合并到索引的最终叶页面。(3)当填充叶页面时,建立非叶页面。如果没有使用SORT_IN_TEMPDB选项, 中间页面将写出到在其中存储数据库的相同物理文件。这意味着实际数据的读必须与构建过程的写竞争。这两种情况造成磁头从另一个(读与写相比)需要的位置移动到不同位置。结果是磁头经常地米回移动—这会花费时间。另一方面, 如果使用SORT_IN_TEMPDB, 那么中间页面将写入到tempdb, 而不是数据库自己的文件。如果它们在独立的物理驱动器上,这意味着在索引构建的读和写操作之间没有竞争。但是, 牢牢记住, 只有在tempdb位于与数据库文件分离的独立物理驱动器上,这才会有效:否则,变化仅仅是在名字上,而且I/O的竞争仍然是相关的因素。提示:如果要使用SORT_IN_TEMPDB, 则确保在tempdb内有用于大文件的足够空间。10.ONLINE如果设置这个选项为ON,那么它迫使表对于一般的访问保持有效,并且不创建任何锁以阻止用户对索引和/或表的使用。默认情况下,全索引操作将获得锁(最终是表的锁),它需要具有对表的完全和有效的访问。然而,副作用是这将会阻止用户。(这是矛盾的;我们可能正在建立索引以使数据库更为有用,但是在做这件事时,我们实际上使表不可用).现在,您可能正在考虑如下事情:“听起来这似乎是一个好主意——我将每次都这样做,以使我的用户不受影响。”这是非常糟糕的想法。牢牢记住,任何类似的索引构造可能是I/O高密集的操作,所以它正在以某种方式或者其他方式影响用户。现在,在针对这一点的索引构建中,需要许多额外的开销来确保它没有阻止任何用户的脚步。当其正在建立索引时, 如果让SQLServer有对表的自由控制, 将能更快地建立索引, 而且构建正在影响您的系统的整体时间将更少。注意:ONLINE索引操作仅仅在SQLServer的企业级版本中支持。在其他的版本里能够执行带有ONLINE指令的索引命令, 但是它将被忽略, 所以在使用较低版本的SQLServer时,如果使用ONLINE井且发现您的用户仍然被索引操作阻止在外, 不要对此感到惊讶.11.ALLOW ROW/PAGE LOCKS这是比ONLINE长的术语指令, 而且是非常高级的主题, 出于本书的目的以及到目前为止关于锁已经介绍的内容,坚持一个相当简单的解释。到现在为止,在本书许多内容中已经重复地使用术语“锁”。正如前面所解释的那样,这在一定程度上是避免数据完整性冲突的占位符, 这里查看的ALLOW设置用于设置关于索引是否允许这些类型锁的指令。这可以归入极端性能调整的主题。12.MAX DOP这是为了构建这个索引而最大化并行程度的首要系统设置。因为并行不在本书的讨论范围之外,所以这里将简要介绍它简而言之,并行的程度是将多少进程用于一个数据库操作(在这种情况下,该操作是索引的构造)。称为最大并行度的系统设置允许您限制每个操作中的处理器数目。当您认为合适时, 在索引创建选项中的MAX DOP选项允许将并行度设置为高于或者低于基本系统设置。13.0NSQLServer提供了从通过使用ON选项的数据中独立存储索引的选项, 从一些观点来看,这种选项可能非常有用:还有更多相关的内容,但是这涉及非常高级的内容。这些内容与数据使用非常相关,所以不会在本书的范围内考虑它。9.3.2创建XML索引XML索引是SQLServer 2005附带的新特性, 这归功于Microsoft的努力。索引如同XML一样无结构的一些内容是许多人尝试完成的问题, 但是几乎没有人具有任何实际成功的实现。SQLServer团队为了荣誉而努力实现这一点。尽管足够热情——开始认真考虑关于XML索引的所有内容。索引需要的空间可以扩展到其他的驱动器巾。索引操作的I/O不会承担物理数据的检索工作。

这是另外一个“鸡和鸡蛋”的事情, 因为到目前为止在本书中还没有真正查看XML。尽管如此, 更多的是将其认为是索引主题, 而不是XML主题。实际上, XML创建的语法支持在前面查看CREATE语句时的所有相同选项, 除了IGNORED UP KEY和ONLINE。不同于迄今为止已经查看的关系型数据, XML倾向于非结构化的数据。它利用标记来识别数据, 并且可以关联模式以提供基于XML数据的类型和确认信息.XML的非结构化性质需要“导航”或者“路径”信息的概念, 用于在XML文档中查找数据“节点”。在另一方面,现在索引尝试并提供给数据特定的结构和顺序——这在一定程度上引起了冲突可以在SQLServer中类型为XML的列上创建索引。实现这一点的基本需求如下:1.主要的XML索引在XML索引上创建的第一个索引必须声明为“主要的”索引。当您创建主要的索引时,SQLServer创建一个新的群集索引, 这个群集索引将基表的群集索引和来自任何您指定的XML节点的数据组合在一起。2.次要的XML索引这里没有任何事情是特殊的——非常类似于指向群集索引的群集键的非群集索引,次要的XML索引以很相似的方法指向主要的XML索引。一日您创建了主要的XML索引, 那么您能在XML列上创建多达248个以上的XML索引。9.3.3使用约束创建的隐含索引我称这个为“偶然的索引”。这不是索引不应当在那里的意思——如果您想要创建索引的约束,那么它不得不在那里。它只是我已经多次看见的糟糕情况,其中在系统上只有索引是以这种方式创建的。通常,这暗示系统管理员和/或设计者实际上对于索引的概念是健忘的。然而,您仍然将要发现关于这一点的另一种奇怪的不同情况——在这种情况中,管理员或设计者知道如何创建索引,但并不真正知道如何说出什么样的索引已经在系统上,以及它们正在做什么。复制的索引是这种情况的典型代表。只要它们有不同的名字, SQLServer将非常乐意于为您创建它们。当如下两种限制中的一个添加到表上时,创建隐含索引:到目前为止已经看到CREATE语法的很多用法, 所以我不会反复地讨论它——但是, 应当注意:当创建作为约束的隐含索引的索引时, 不允许除了{CLUSTEREDNON CLUSTERED和FILL FACTOR之外的所有的项。9.4明智的选择:在何处以及何时使用何种索引到现在,您可能正在认为自己:“我总是将要创建群集索引!”有许多以这种方式考虑的很好的理由,只需要记住也有一些理由不这么做。选择包含何种索引以及不包含何种索引是一个艰苦的过程,而且,万一信息不足够,您不得不对您需要的索引类型做出一些决定。如果只有一个群集索引,则同时较容易和较难地进行后面的决定。它意味着您不得不明智地选择以最有效地使用它。9.4.1选择性索引,特别是非群集索引,主要在索引内有合理的高级选择性的情况下是有益的。通过选择性,我正在引用列中唯一值的百分比。列中唯一值的百分比越高,选择性就越高,并且索引的益处就越大。如果您回顾关于非群集索引的章节——特别是关于非群集索引和群集索引比较的章节――您将重新回忆起在非群集索引中的查询实际上只是开始,您仍然需要执行另一个通过群集索引的循环以找到实际的数据。甚至使用堆上的非群集索引,您仍然最终需要执行多个物理上分离的读操作,如果在非群集索引中的一个查找将要在群集索引上产生多个额外的查找,那么以表扫描的方式可能情况较好。这里可能的指数影响实际上非常令人惊讶。如果您没有在索引列的90%-95%唯一性区域中的某个位置,那么考虑由非群集索引创建的循环过程是不值得的。群集索引在实质上较少地受到这一点影响,这是因为一旦您在数据范围的开始位置——唯一的或非唯一的——您就在那里。没有额外的用于读的索引页面。尽管如此,更可能的情况是您的群集索引具有可能更多使用的其他内容。关于选择性规则的另一种例外情况必须利用外键。如果您的表有一个作为外键的列,在所有的可能性中,您将得益于


《SQL Server 2005编程入门经典》目录

计算机


python
AI人工智能
javascript
计算机网络/服务器
数据库技术
计算机F

考试教辅


考研考博
英语四六级

沪ICP备18046276号-5