做者:David Durant,2014/11/05(首次发布:2011/02/17)sql
本文属于进阶系列的:Stairway to SQL Server Indexes数据库
索引是数据库设计的基础,并告诉开发人员使用数据库大量关于设计人员的意图。不幸的是,当性能问题出现时,索引一般被添加为过后的想法。最后这一系列简单的文章,应该能使任何数据库专业人员快速的“加快速度”。并发
此第一级引入SQL Server索引:数据库对象,使SQL Server可以在最短期内查找和/或修改所请求的数据,使用最少的系统资源实现最大性能。良好的索引还将容许SQL Server实现最大的并发性,以便一个用户运行的查询对其余人运行的查询几乎没有影响。最后,索引提供了一种实现数据完整性的有效方法,经过在建立惟一索引时保证键值的惟一性。这个级别是一个介绍;它涵盖了概念和用法,但将物理细节留给了更高的层次。数据库设计
对数据库开发人员的透彻理解对于数据库开发人员来讲很是重要,其中一个缘由来自于全部其余缘由:当SQL Server从客户端到达的请求时,SQL Server只有两种可能的方式来访问所请求的行:sqlserver
由于索引具备与它们相关联的开销(它们占用空间而且必须与表保持同步),因此它们不是SQL Server所必需的。彻底没有索引的数据库是可能的。它可能会执行得不好,必定会有数据完整性问题,但SQL Server将容许它。性能
可是,这不是咱们想要的。咱们都但愿数据库运行良好,具备数据完整性,同时将索引开销降至最低。这个水平将使咱们开始实现这一目标。spa
在这个楼梯中,咱们将用例子来讲明关键概念。 这些示例基于Microsoft AdventureWorks示例数据库。 咱们专一于销售订单功能。 五个表将给咱们很好的组合事务和非交易数据; 客户,SalesPerson,产品,SalesOrderHeader和SalesOrderDetail。 为了保持重点,咱们使用一列子集。设计
AdventureWorks正常化,因此销售人员信息被分为三个表格: 销售人员,员工和联系人。 对于一些例子,咱们将它们视为单个表。 咱们将使用的完整的表,以及它们之间的关系,如图1.1所示。code
图1.1:将在此楼梯中使用的AdventureWorks表server
注意:
此楼梯级别中显示的全部TSQL代码能够与文章一块儿下载(请参阅本文底部的连接)
咱们开始对索引的研究,一个简短的故事,一个使用一个旧的并且被证实的技术,咱们在本文中将引用索引的基本概念。
你离开你的房子跑几个差事。当你回来的时候,你会发现你女儿垒球教练的消息等着你。三个女孩,特雷西,丽贝卡,艾米已经失去了球队帽。你能摆脱竞技产品店,买女孩的帽子。他们的父母会在下一场比赛中报销你。
你知道女孩,你知道他们的父母。但你不知道他们的帽子大小。在你镇的某个地方有三个住宅,每一个都有一个您须要的信息。没问题,你只要打电话给父母,获得帽子的大小。您能够拨打手机,而后到达索引 - 电话簿的白页。
您须要达到的第一个住所是Helen Meyer。估计“迈耶”将位于人口中部附近,你跳到白页的中间;只发现你在页面上的标题为“Kline-Koerber”。你进一步向前跳,到达“Niger-Nyeong”页面。一个甚至更小的跳跃让你进入“马尔多纳多 - 尼格尔”页面。意识到您如今在正确的页面,您扫描页面,直到您到达“迈耶,海伦”行并得到电话号码。使用电话号码,您能够到达迈耶居所,并获取您须要的信息。
您再重复一次这个过程,再到另外两个居住地,再得到两个帽子大小。
你刚刚使用了一个索引,而且使用它与SQL Server使用索引的方式大体相同。由于有很大的类似之处,以及白皮书和SQL Server索引之间的一些区别。
实际上,您刚刚使用的索引表明SQL Server支持的两个SQL Server索引类型:集群和非聚簇。白页最好表明非聚簇索引的概念。所以,在这个层次上,咱们引入非聚簇索引。后续级别将引入集群索引,并对这两种类型进行更深刻的挖掘。
白页相似于非聚簇索引,由于它们不是数据自己的组织;而是一种机制或地图来帮助您访问该数据。数据自己就是咱们须要联系的实际人员。电话公司不会安排该镇的住宅有意义的顺序,将房屋从一个位置移动到另外一个位置,以使同一垒球队中的全部女孩彼此隔壁相隔,房屋不按居民姓氏组织。相反,它给你一本书包含每一个住所的一个条目。这些条目由白页的搜索关键字排序;姓氏,名字,中间初始和街道地址。每一个条目都包含搜索关键字和使您能够访问住所的数据;电话号码。
像一个条目白皮书,SQL Server非聚簇索引中的每一个条目都包含两部分:
此外,SQL Server非聚簇索引条目具备一些仅内部使用的头信息,而且可能包含一些可选信息。这两个都将在之后的层面上予以涵盖;此时对于非聚簇索引的理解也不重要。
像白页同样,在搜索关键字序列中维护一个SQL Server索引,以即可以在一组小的“跳转”中访问任何特定的条目。给定搜索关键字,SQL Server能够快速获取该密钥的索引条目。与白页不一样,SQL Server索引是动态的。也就是说,SQL Server会在每次添加,删除行或修改搜索关键字列值时更新索引。
正如白页中的条目序列与城镇内的住宅地理序列不一样;非聚簇索引中的条目序列与表中的行序列不一样。索引中的第一个条目多是表中最后一行,索引中的第二个条目多是表中第一行。若是事实与索引不一样,索引始终是有意义的序列;表的行能够彻底没有排序。
建立索引时,SQL Server会在基础表中的每一行的索引中生成并维护一个条目(当覆盖过滤后的索引时,将会遇到此通用规则的一个例外)。您能够在表上建立多个非聚簇索引,但不能包含包含来自多个表的数据的索引。
而最大的区别是:SQL Server不能使用电话。它必须使用索引条目的书签部分中的信息导航到表的相应行。当SQL Server须要数据行中的任何信息,但不在相应的索引条目中时,这将是必需的,例如Tracy Meyer的垒球帽大小。因此,为了更好的比喻,白页的条目包含一组GPS坐标而不是一个电话号码。而后,使用GPS坐标导航到由白页条目表示的住宅。
咱们经过两次查询咱们的示例数据库来结束这个级别。 确保您正在使用适用于SQL Server 2005的AdventureWorks版本,可由SQL Server 2008使用。AdventureWorks2008数据库具备不一样的表结构,下面的查询将失败。 咱们每次都会运行相同的查询; 但在咱们在表上建立一个索引以前,第一个执行将会发生,第二个执行将在咱们建立一个索引以后。 每次SQL Server会告诉咱们在检索所请求的信息方面作了多少工做。 咱们将在咱们的联系表中找到“Helen Meyer”行(她的行位于表的中间附近)。 最初,表不会在FirstName列或LastName列上有一个索引。 为确保您能够屡次运行示例,请确保咱们将在第三批中构建的索引不存在,方法是运行如下代码:
IF EXISTS (SELECT * FROM sys.indexes WHERE OBJECT_ID = OBJECT_ID('Person.Contact') AND name = 'FullName') DROP INDEX Person.Contact.FullName;
清单1.1 - 确保索引不存在
咱们的任务将须要四个SQL命令批处理。
第一个命令批次:
SET STATISTICS io ON SET STATISTICS time ON GO
清单1.2 - 开启统计
上述批次通知SQL Server,咱们但愿咱们的查询做为输出的一部分返回性能信息。
第二个命令批次:
SELECT * FROM Person.Contact WHERE FirstName = 'Helen' AND LastName = 'Meyer'; GO
清单1.3 - 检索一些数据
第二批检索“Helen Meyer”行:
584 Helen Meyer helen2@adventure-works.com 0-519-555-0112
再加上如下性能信息:
Table 'Contact'. Scan count 1, logical reads 569. SQL Server Execution Times: CPU time = 3 ms.
该输出通知咱们,咱们的请求执行了569个逻辑IO,而且须要大约3毫秒的处理器时间来执行此操做。 您的处理器时间值可能不一样。
第三个命令批次:
CREATE NONCLUSTERED INDEX FullName ON Person.Contact ( LastName, FirstName ); GO
清单1.4 - 建立非汇集索引
此批次在联系人表的名字和姓氏列上建立非聚簇复合索引。 复合索引是具备多个列的索引,肯定索引行序列。
第四个命令批次:
SELECT * FROM Person.Contact WHERE FirstName = 'Helen' AND LastName = 'Meyer'; GO
清单1.3(再次)
最后一批是从新执行咱们原始的SELECT语句。 咱们获得与之前同样返回的同一行; 可是此次性能统计数据是不一样的
Table 'Contact'. Scan count 1, logical reads 4. SQL Server Execution Times: CPU time = 0 ms.
该输出通知咱们,咱们的请求只须要4个逻辑IO; 而且须要很是少许的处理器时间来检索“Helen Meyer”行。
建立精心挑选的索引能够大大提升数据库性能。 在下一级,咱们将开始研究索引的物理结构。 咱们将研究为何这个非汇集索引对这个查询是如此有益的,为何可能并不老是这样。 将来的水平将涵盖其余类型的指数,指数的附加利益,与索引相关的成本,监控和维护您的指数以及最佳作法; 全部这些都旨在为您提供必要的知识,为您本身的数据库中的表建立最佳的索引计划。
Level 1 - IntroToIndexes_Durant_Code.sql | Level 1 - MillionRowContactTable.sql