聚集索引、非聚集索引、主键、索引 大杂烩【转】 - TOMMYHU - 专注互联网开发及运营技术,提供相关资料及软件下载,奇趣网络时事评论!
Jul 24

聚集索引、非聚集索引、主键、索引 大杂烩【转】 不指定

tommyhu , 23:20 , DBA , Comments(1) , Trackbacks(0) , Reads(5684) , Via Original Large | Medium | Small

 

一、特点

索引是在数据库表或者视图上创建的对象,目的是为了加快对表或视图的查询的速度

按照存储方式分为:聚集索引与非聚集索引
按照维护与管理索引角度分为:唯一索引、复合索引和系统自动创建的索引

索引的结构是由:根节点--->非叶节点--->非叶节点--->叶节点


1、聚集索引:表中存储的数据按照索引的顺序存储,检索效率比普通索引高,但对数据新增/修改/删除的影响比较大
特点:
 
  (1) 一个表可以最多可以创建249个索引
  (2) 先建聚集索引才能创建非聚集索引
   (3) 非聚集索引数据与索引不同序
   (4) 数据与索引在不同位置
   (5) 索引在叶节点上存储,在叶节点上有一个"指针"直接指向要查询的数据区域
   (6) 数据不会根据索引键的顺序重新排列数据
   
 创建聚集索引的语法:
  create NONCLUSTERED INDEX idximpID ON EMP(empID)
2、非聚集索引:不影响表中的数据存储顺序,检索效率比聚集索引低,对数据新增/修改/删除的影响很少
特点:
  (1) 无索引,数据无序
  (2) 有索引,数据与索引同序 
  (3) 数据会根据索引键的顺序重新排列数据
  (4) 一个表只能有一个索引
  (5) 叶节点的指针指向的数据也在同一位置存储
语法:
create CLUSTERED INDEX idxempID on emp(empID)
3、惟一索引:惟一索引可以确保索引列不包含重复的值.
可以用多个列,但是索引可以确保索引列中每个值组合都是唯一的
姓  名
李  二
张  三
王  五
语法: create unique index idxempid on emp(姓,名)

4、复合索引:如果在两上以上的列上创建一个索引,则称为复合索引。
那么,不可能有两行的姓和名是重复的
语法:
create index indxfullname on addressbook(firstname,lastname)

5、系统自建的索引:在使用T_sql语句创建表的时候使用PRIMARY KEY或UNIQUE约束时,会在表上自动创建一个惟一索引
自动创建的索引是无法删除的
语法:
create table ABc
( empID int primary key,
  firstname varchar(50)UNIQUE,
  lastname  varchar(50)UNIQUE,
)
这样的结果就出来了三个索引,但只有一个聚集索引

 二、描述


在数据库中通过什么描述聚集索引与非聚集索引的?

索引是通过二叉树的形式进行描述的,聚集索引的叶节点就是最终的数据节点,而非聚集索引的叶节仍然是索引节点,但它有一个指向最终数据的指针。


主键(PRIMARY KEY )  
表通常具有包含唯一标识表中每一行的值的一列或一组列,这样的一列或多列称为表的主键 (PK)。

用于强制表的实体完整性。在创建或修改表时,您可以通过定义 PRIMARY KEY 约束来创建主键。一个表只能有一个 PRIMARY KEY 约束,并且 PRIMARY KEY 约束中的列不能接受空值。由于 PRIMARY KEY 约束可保证数据的唯一性,因此经常对标识列定义这种约束。如果为表指定了 PRIMARY KEY 约束,则 SQL Server 2005 数据库引擎 将通过为主键列创建唯一索引来强制数据的唯一性。当在查询中使用主键时,此索引还可用来对数据进行快速访问。因此,所选的主键必须遵守创建唯一索引的规则。 

创建主键时,数据库引擎 会自动创建唯一的索引来强制实施 PRIMARY KEY 约束的唯一性要求。如果表中不存在聚集索引或未显式指定非聚集索引,则将创建唯一的聚集索引以强制实施 PRIMARY KEY。

汉语字典的正文本身就是一个聚集索引。

比如,我们 要查“安”字,就会很自然地翻开字典的前几页,因为“安”的拼音是“an”,而按照拼音排序汉字的字典是以英文字母“a”开头并以“z”结尾的,那么 “安”字就自然地排在字典的前部。如果您翻完了所有以“a”开头的部分仍然找不到这个字,那么就说明您的字典中没有这个字;同样的,如果查“张” 字,那您也会将您的字典翻到最后部分,因为“张”的拼音是“zhang”。也就是说,字典的正文部分本身就是一个目录,您不需要再去查其他目录来找到您需 要找的内容。正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。

如果您认识某个字,您可以快速地从自动中查到这个字。但您也可能会遇到您不认识的字,不知道它的发音,这时候,您就不能按照刚才的方法找到您要查的字,而 需要去根据“偏旁部首”查到您要找的字,然后根据这个字后的页码直接翻到某页来找到您要找的字。但您结合“部首目录”和“检字表”而查到的字的排序并不是 真正的正文的排序方法,比如您查“张”字,我们可以看到在查部首之后的检字表中“张”的页码是672页,检字表中“张”的上面是“驰”字,但页码却是63 页,“张”的下面是“弩”字,页面是390页。很显然,这些字并不是真正的分别位于“张”字的上下方,现在您看到的连续的“驰、张、弩”三字实际上就是他 们在非聚集索引中的排序,是字典正文中的字在非聚集索引中的映射。我们可以通过这种方式来找到您所需要的字,但它需要两个过程,先找到目录中的结果,然后再翻到您所需要的页码。我们把这种目录纯粹是目录,正文纯粹是正文的排序方式称为“非聚集索引”。
通过以上例子,我们可以理解到什么是“聚集索引”和“非聚集索引”。


每个表只能有一个聚集索引,因为目录只能按照一种方法进行排序。聚集索引插入数据时速度要慢(时间花费在“物理存储的排序”上,也就是首先要找到位置然后插入)查询数据比非聚集数据的速度快。

三、区别比较

 

聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个。

 

聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续。


聚集索引用与不用比较

1、用聚合索引比用不是聚合索引的主键速度快查询速度快

2、用聚合索引比用一般的主键作order by时速度快,特别是在小数据量情况下

3、使用聚合索引内的时间段,搜索时间会按数据占整个数据表的百分比成比例减少,而无论聚合索引使用了多少个

4 、日期列不会因为有分秒的输入而减慢查询速度

从publish 表中取出第 n 条到第 m 条的记录:
SELECT TOP m-n+1 *
FROM publish
WHERE (id NOT IN
(SELECT TOP n-1 id
FROM publish))

id 为publish 表的关键字

只所以把“查询优化”和“分页算法”这两个联系不是很大的论题放在一起,就是因为二者都需要一个非常重要的东西――聚集索引

在前面的讨论中我们已经提到了,聚集索引有两个最大的优势:

1、以最快的速度缩小查询范围。

2、以最快的速度进行字段排序。

第1条多用在查询优化时,而第2条多用在进行分页时的数据排序。
聚集索引在每个表内又只能建立一个,这使得聚集索引显得更加的重要。

聚集索引的挑选可以说是实现“查询优化”和“高效分页”的最关键因素。


聚集索引是如此的重要和珍贵,所以一定要将聚集索引建立在:

1、您最频繁使用的、用以缩小查询范围的字段上;

2、您最频繁使用的、需要排序的字段上。


四、结合实际,谈索引使用的误区

  理论的目的是应用。虽然我们刚才列出了何时应使用聚集索引或非聚集索引,但在实践中以上规则却很容易被忽视或不能根据实际情况进行综合分析。下面我们将根据在实践中遇到的实际问题来谈一下索引使用的误区,以便于大家掌握索引建立的方法。

 

  1、主键就是聚集索引

 

  这种想法笔者认为是极端错误的,是对聚集索引的一种浪费。虽然SQL SERVER默认是在主键上建立聚集索引的。

 

  通常,我们会在每个表中都建立一个ID列,以区分每条数据,并且这个ID列是自动增大的,步长一般为1。我们的这个办公自动化的实例中的列 Gid就是如此。此时,如果我们将这个列设为主键,SQL SERVER会将此列默认为聚集索引。这样做有好处,就是可以让您的数据在数据库中按照ID进行物理排序,但笔者认为这样做意义不大。

 

  显而易见,聚集索引的优势是很明显的,而每个表中只能有一个聚集索引的规则,这使得聚集索引变得更加珍贵。

 

  从我们前面谈到的聚集索引的定义我们可以看出,使用聚集索引的最大好处就是能够根据查询要求,迅速缩小查询范围,避免全表扫描。在实际应用中, 因为ID号是自动生成的,我们并不知道每条记录的ID号,所以我们很难在实践中用ID号来进行查询。这就使让ID号这个主键作为聚集索引成为一种资源浪 费。其次,让每个ID号都不同的字段作为聚集索引也不符合大数目的不同值情况下不应建立聚合索引规则;当然,这种情况只是针对用户经常修改记录内容,特别 是索引项的时候会负作用,但对于查询速度并没有影响。

 

  在办公自动化系统中,无论是系统首页显示的需要用户签收的文件、会议还是用户进行文件查询等任何情况下进行数据查询都离不开字段的是日期还有用户本身的用户名。

 

  通常,办公自动化的首页会显示每个用户尚未签收的文件或会议。虽然我们的where语句可以仅仅限制当前用户尚未签收的情况,但如果您的系统已 建立了很长时间,并且数据量很大,那么,每次每个用户打开首页的时候都进行一次全表扫描,这样做意义是不大的,绝大多数的用户1个月前的文件都已经浏览过 了,这样做只能徒增数据库的开销而已。事实上,我们完全可以让用户打开系统首页时,数据库仅仅查询这个用户近3个月来未阅览的文件,通过日期这个字段来限 制表扫描,提高查询速度。如果您的办公自动化系统已经建立的2年,那么您的首页显示速度理论上将是原来速度8倍,甚至更快。

 

  在这里之所以提到理论上三字,是因为如果您的聚集索引还是盲目地建在ID这个主键上时,您的查询速度是没有这么高的,即使您在日期这个字段上建立的索引(非聚合索引)。下面我们就来看一下在1000万条数据量的情况下各种查询的速度表现(3个月内的数据为25万条):

 

  (1)仅在主键上建立聚集索引,并且不划分时间段:

 

Select gid,fariqi,neibuyonghu,title from tgongwen

 

  用时:128470毫秒(即:128秒)

 

  (2)在主键上建立聚集索引,在fariq上建立非聚集索引:

 

select gid,fariqi,neibuyonghu,title from Tgongwenwhere fariqi>dateadd(day,-90,getdate())

 

  用时:53763毫秒(54秒)

 

  (3)将聚合索引建立在日期列(fariqi)上:

 

select gid,fariqi,neibuyonghu,title from Tgongwenwhere fariqi>dateadd(day,-90,getdate())

 

  用时:2423毫秒(2秒)

 

  虽然每条语句提取出来的都是25万条数据,各种情况的差异却是巨大的,特别是将聚集索引建立在日期列时的差异。事实上,如果您的数据库真的有 1000万容量的话,把主键建立在ID列上,就像以上的第1、2种情况,在网页上的表现就是超时,根本就无法显示。这也是我摒弃ID列作为聚集索引的一个 最重要的因素。得出以上速度的方法是:在各个select语句前加:

 

declare@ddatetimeset@d=getdate()

 

  并在select语句后加:

 

select[语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())

 

  2、只要建立索引就能显著提高查询速度

 

  事实上,我们可以发现上面的例子中,第2、3条语句完全相同,且建立索引的字段也相同;不同的仅是前者在fariqi字段上建立的是非聚合索引,后者在此字段上建立的是聚合索引,但查询速度却有着天壤之别。所以,并非是在任何字段上简单地建立索引就能提高查询速度。

 

  从建表的语句中,我们可以看到这个有着1000万数据的表中fariqi字段有5003个不同记录。在此字段上建立聚合索引是再合适不过了。在 现实中,我们每天都会发几个文件,这几个文件的发文日期就相同,这完全符合建立聚集索引要求的:既不能绝大多数都相同,又不能只有极少数相同的规则。由此 看来,我们建立适当的聚合索引对于我们提高查询速度是非常重要的。

 

  3、把所有需要提高查询速度的字段都加进聚集索引,以提高查询速度

 

  上面已经谈到:在进行数据查询时都离不开字段的是日期还有用户本身的用户名。既然这两个字段都是如此的重要,我们可以把他们合并起来,建立一个复合索引(compound index)。

 

  很多人认为只要把任何字段加进聚集索引,就能提高查询速度,也有人感到迷惑:如果把复合的聚集索引字段分开查询,那么查询速度会减慢吗?带着这 个问题,我们来看一下以下的查询速度(结果集都是25万条数据):(日期列fariqi首先排在复合聚集索引的起始列,用户名neibuyonghu排在 后列):

 

1select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>''2004-5-5''查询速度:2513毫秒
2select gid,fariqi,neibuyonghu,title from Tgongwen 
where fariqi>''2004-5-5''and neibuyonghu=''办公室''查询速度:2516毫秒
3select gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu=''办公室''查询速度:60280毫秒

 

  从以上试验中,我们可以看到如果仅用聚集索引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询速度是几乎一样的,甚至比用上全部的复合索引 列还要略快(在查询结果集数目一样的情况下);而如果仅用复合聚集索引的非起始列作为查询条件的话,这个索引是不起任何作用的。当然,语句1、2的查询速 度一样是因为查询的条目数一样,如果复合索引的所有列都用上,而且查询结果少的话,这样就会形成索引覆盖,因而性能可以达到最优。同时,请记住:无论您是 否经常使用聚合索引的其他列,但其前导列一定要是使用最频繁的列。

 

  五、索引使用经验总结

 

  1、用聚合索引比用不是聚合索引的主键速度快

 

  下面是实例语句:(都是提取25万条数据)

 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16''

 

  使用时间:3326毫秒

 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid<=250000

 

  使用时间:4470毫秒

 

  这里,用聚合索引比用不是聚合索引的主键速度快了近1/4。

 

  2、用聚合索引比用一般的主键作order by时速度快,特别是在小数据量情况下

 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen orderby fariqi

 

  用时:12936

 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen orderby gid

 

  用时:18843

 

  这里,用聚合索引比用一般的主键作order by时,速度快了3/10。事实上,如果数据量很小的话,用聚集索引作为排序列要比使用非聚集索引速度快得明显的多;而数据量如果很大的话,如10万以上,则二者的速度差别不明显。

 

  3、使用聚合索引内的时间段,搜索时间会按数据占整个数据表的百分比成比例减少,而无论聚合索引使用了多少个:

 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>''2004-1-1''

 

  用时:6343毫秒(提取100万条)

 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>''2004-6-6''

 

  用时:3170毫秒(提取50万条)

 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=''2004-9-16''

 

  用时:3326毫秒(和上句的结果一模一样。如果采集的数量一样,那么用大于号和等于号是一样的)

 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen
where fariqi>''2004-1-1''and fariqi<''2004-6-6''

 

  用时:3280毫秒

 

  4、日期列不会因为有分秒的输入而减慢查询速度

 

  下面的例子中,共有100万条数据,2004年1月1日以后的数据有50万条,但只有两个不同的日期,日期精确到日;之前有数据50万条,有5000个不同的日期,日期精确到秒。

 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen
where fariqi>''2004-1-1''orderby fariqi

 

  用时:6390毫秒

 

select gid,fariqi,neibuyonghu,reader,title from Tgongwen
where fariqi<''2004-1-1''orderby fariqi

 

  用时:6453毫秒


 

得出查询速度的方法是:

在各个select语句前加:declare @d datetime
set @d=getdate()
并在select语句后加:
select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())


六、何时使用聚集索引非聚集索引

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
            

动作描述

            
            

使用聚集索引

            
            

使用非聚集索引

            
            

列经常被分组排序

            
            

            
            

            
            

返回某范围内的数据

            
            

            
            

不应

            
            

一个或极少不同值

            
            

不应

            
            

不应

            
            

小数目的不同值

            
            

            
            

不应

            
            

大数目的不同值

            
            

不应

            
            

            
            

频繁更新的列

            
            

不应

            
            

            
            

外键列

            
            

            
            

            
            

主键列

            
            

            
            

            
            

频繁修改索引列

            
            

不应

            
            

            

 

七、主键和聚集索引的比较

 

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
主键聚集索引
用途强制表的实体完整性对数据行的排序,方便查询用
一个表多少个一个表最多一个主键一个表最多一个聚集索引
是否允许多个字段来定义一个主键可以多个字段来定义一个索引可以多个字段来定义
   
是否允许 null 数据行出现如果要创建的数据列中数据存在null,无法建立主键。
            创建表时指定的 PRIMARY KEY 约束列隐式转换为 NOT NULL。
没有限制建立聚集索引的列一定必须 not null .
            也就是可以列的数据是 null
            参看最后一项比较
是否要求数据必须唯一要求数据必须唯一数据即可以唯一,也可以不唯一。看你定义这个索引的 UNIQUE 设置。
            (这一点需要看后面的一个比较,虽然你的数据列可能不唯一,但是系统会替你产生一个你看不到的唯一列)
   
创建的逻辑数据库在创建主键同时,会自动建立一个唯一索引。
            如果这个表之前没有聚集索引,同时建立主键时候没有强制指定使用非聚集索引,则建立主键时候,同时建立一个唯一的聚集索引
如果未使用 UNIQUE 属性创建聚集索引,数据库引擎 将向表自动添加一个四字节 uniqueifier 列。
            必要时,数据库引擎 将向行自动添加一个 uniqueifier 值,使每个键唯一。此列和列值供内部使用,用户不能查看或访问。


 
 
 

▲返回顶部

互联网开发网友
2014/02/04 15:47
求解原文:如果您的办公自动化系统已经建立的2年,那么您的首页显示速度理论上将是原来速度8倍,甚至更快。
Pages: 1/1 First page 1 Final page
Add a comment

Nickname

emotemotemotemotemotemotemotemotemotemotemotemotemotemotemotemot