17xie > SQL Server 2005高级程序设计 > 第3章 SQL Server——存储和索引结构
背景:                 
[本书目录] [图书首页] [本书讨论区]  
链接地址:http://www.17xie.com/read-105390.html    注册17xie 一起来写书 实现您的出书梦想!

第3章 SQL Server——存储和索引结构

引是数据库规划和系统维护中至关重要的部分。它们为SQL Server(就此而言,还有其他数据库系统)提供另外的查找数据的手段,并通过捷径抵达数据的物理位置。添加正确的索引能够极大减少查询的执行时间。遗憾的是,许多的设计糟糕的查询实际上会增加执行查询的时间。事实上,索引是SQL Server提供的对象中最容易误解的对象之一,因而也倾向于成为最容易处理失当的对象之一。

本章将既从开发者又从管理员的视角来深入学习索引。不过,为了理解索引,还必须了解数据是如何在数据库中存储的。鉴于此,本章中也要讨论SQL Server的数据存储机制,包括SQL Server使用的索引分配策略以及内在结构。

3.1  SQL Server存储

可以把SQL Server中的数据想成是存储在某种层次结构中的数据。这种层次非常简单。层次中的一些对象是你将直接处理的,因而很容易了解。许多其他的对象则存在于保护之下,虽然在一些情况下能够直接处理它们,但通常是不行的。下面来逐一讲解。

3.1.1  数据库

数据库是比较容易的概念。有读者或许会说着“我已经都知道了。”是的,很可能大家都知道,但是,由于它是存储定义的最高级别(对于一个指定的服务器而言),因而这里作为一个独立的实体指出它。数据库是能够建立锁的最高级别,不过无法显式地创建数据库级别的锁。

锁是系统使用的某种控制和位置标记。第12章将全面讲述锁,但是,当我们讲述存储时,会顺便讨论到SQL Server中对象的可锁定性。

3.1.2  文件

默认情况下,与数据库有关的文件有两种:

l    第一种是主物理数据库文件——它是数据最终存储的地方。应当以*.mdf为扩展名命名这种文件(这是推荐的方法,并不是必须如此——不过,你会发现以别的方式命名将随着时间的推移而变得让人迷惑)。

l    第二种是数据库文件的某种分支——日志。在第12章中讲述事务和锁时,会深入研究日志,这里应该明白日志保存在于它自己的文件中(应当以*.ldf为扩展名)。并且,没有了它数据库将无法工作。日志是从最后一次把数据“提交”到数据库中以来,发生在数据库上的事情的连续记录。实际上,数据库不是完整的数据集。日志不是完整的数据集。只有从数据库入手,并“应用”(从中添加所有的活动)日志,才能拥有完整的数据集。

对于这些文件相互之间如何放置没什么限制。可以把每一个文件放在单独的物理设备上(实际上,甚至很需要这样做)。这不仅允许一个文件中的活动不会影响到另一个文件中的活动,而且还创造出这样的情形:当数据库文件受损时,不会导致损失所做的工作——可以恢复备份然后重新应用日志(它安全地存放在另一个驱动器上)。同样,如果损失的是存放日志的驱动器,仍然能获得到最近的检查点时间的有效的数据库(在关于锁和事务的章节中将全面讲述检查点)。

3.1.3  区段

区段(extent)是用来为表和索引分配空间的基本存储单元。它由8个连续的数据页组成(64K)。

基于区段而不是实际使用的空间来分配空间的概念,对习惯于操作系统存储原则的人来说,多少有点难以理解。关于区段的要点包括:

l    一旦一个区段已满,下一条记录将占用一个完整的新区段的大小,而不是记录本身的大小。许多新接触SQL Server的人在空间估算上失误,部分是由于一次分配的是一个区段而非一条记录的大小。

l    通过预先分配空间,SQL Server省下了为每一条记录分配新空间的时间。

仅仅因为要添加的行比现在分配的区段所能容纳的行多了一行,就要另外占用整个区段,这似乎是一种浪费。但是,以这种方式浪费的空间总量通常不那么多。然而,它们会积少成多(特别是在高度碎片化的环境中),因此你一定要紧记。

占用整个区段空间的好处是SQL Server省去了一些分配空间的时间上的开销。SQL Server不必每写入一行就考虑分配问题,而是在需要新的区时才处理额外空间的分配。

别把区段所占用的空间与数据库占用的空间混为一谈。分配给数据库的空间是从硬盘可用空间中消失的空间。区段的空间则仅仅是在数据库获得的整个空间中分配的空间。

3.1.4  页

标头

 
文本框:  
图  8-1

与区是数据库中的分配单元类似,页是特定区段中的分配单元。每一个区段有8个页。

数据行

 

数据行

 

数据行

 

可用空间

 
页是到达真正的数据行的最后一个级别。尽管每个区段中页的数目是固定的,但是页中的行数是不固定的——这完全取决于行的大小,是可变的。可以把页想成是表和索引行数据的某种容器。不允许行跨页。

行偏移量

 
图8-1展示了数据是如何放置在行中的。对于插入的每一行,为了表明特定行的数据开始于页中的何处,注意我们是怎样把行偏移量放置在页的末尾的。

有很多种不同的页类型。鉴于本书的目的,这里关心如下的类型:

l    数据;

l    索引;

l    二进制大型对象(BLOB)(用于Image以及大多数的Text和Ntext数据);

l    全局分配映射表(GAM)和共享全局分配映射表(SGAM);

l    页可用空间(PFS);

l    索引分配映射(IAM);

l    大容量更改映射表;

l    差异更改映射表。

1.数据页

数据页是不言自明的——它们是表中实际的数据,除了所有没有使用text in row选项定义的BLOB数据之外。当行中有一个列包含BLOB数据时,常规的数据存储在数据页中——通常有一个16字节的指针指向BLOB页,该页包含构成BLOB的二进制信息。当使用了text in row选项时,如果文本短到能够放入可用的页面空间中,则把文本与数据存储在一起(否则,依然会使用16字节指针)。

2.索引页

索引页也非常简单明了:它们保存非聚集索引的非叶级页和叶级页(在本章的后面将考查它们是什么),以及聚集索引的非叶级页。当继续本章的学习时,将明了这些索引类型。

3.BLOB页

BLOB页用于存储二进制大型对象。对于SQL Server来说,它们是所有存储在Image字段中的数据以及绝大多数的Text和Ntext数据。由于BLOB页中没有任何行,就数据存储页而言BLOB页是特殊的。既然BLOB的大小能够达到2GB,因而它们必须多于一个页——就这部分,说法是什么并不重要。为了存储整个BLOB,SQL Server将分配它所需的足够多的页,但不保证这些页是连续的——页可以位于数据库文件中的任何地方。

正如前面说过的,在行中的非blob数据和与该行有关的BLOB数据之间,以指针的形式联系在一起。在SQL Server的7.0版本中,指针的性质以及SQL Server如何导航到BLOB数据的方式发生了改变。在6.5版本及以前,BLOB页以链的形式放在一起——类似于链表。要找到任何是BLOB的一部分的页,必须从链表的起始部分开始,一页一页地在BLOB中导航。如果试图进行某种文本或二进制形式的搜索,这种排列将是致命的,因为不得不陷入数据的串行扫描中。然而,从7.0版开始有了改变,页被组织为了B树结构(本章稍后将对此做充分的讨论)。B树提供了一种有更多分支的结构,因此,为更大型的BLOB提供了更直达的路线。这在文本操作能够执行得多快上产生了很大的不同。

即使BLOB的执行性能在7.0版中有了显著提高,它依然很慢,因此,当后面讲述高级的设计问题时,将讨论另一种存储方法。

4.全局分配映射表、共享全局分配映射表和页可用空间页

全局分配映射表(GAM)、共享全局分配映射表(SGAM)和页可用空间(PFS)页类型涉及确定哪些区和页在使用、哪些没在使用。本质上,这些页存储的是说明哪些空间可用的记录。其实,完成高质量的开发或系统管理并非一定要理解这些页的类型,而且,这些内容已经超越了本书的讲述范围。尽管如此,如果你非常想了解它们,可以在联机丛书中找到更多关于它们的信息——在索引中查找GAM即可。

5.大容量更改映射表

由于现在还没有讨论过大容量操作,我们该怎么讲述这一主题呢……

SQL Server中有“大容量操作”的概念。大容量操作是对数据库非常快速的更改(通常是大规模的数据导入或截断表)。这样的速度部分来自于大容量操作不“记录”它们所做的每一件事情。日志对于备份和恢复系统是至关重要的,而大容量操作意味着数据库中发生了没有记入日志的活动(它会记录进行了某些操作,但不记录操作的详情,因而日志无法重建所做的事情)。

大容量更改映射表(BCM)是一组用于跟踪哪些区通过大容量操作进行了修改的页。它对于修改的细节不感兴趣——只关心你对特定的区作了改动。由于知道该区发生了改变,在备份数据库时,它能提供更多的选择。更明确地说,当进行日志备份时,能够对受大容量操作影响的区上的物理数据进行备份,以此作为对日志备份的补充。

6.差异更改映射表

它与大容量更改映射表几乎一样,只不过,它不是只跟踪被大容量操作更改的区,它跟踪自最后一次备份数据库以来发生了更改的所有区。

当请求进行差异备份时,差异更改映射表(DCM)提供什么区需要备份的信息。由于备份只包含自上一次备份以来发生过改动的区,因此该备份更小且速度更快(虽然只是部分的)。

7.页拆分

页满时,会对其做拆分。这意味着不仅要分配一个新页,而且,要把现有页上大约一半的数据移动到新页上。

关于这一过程的例外情况是使用了聚集索引的时候。如果存在聚集索引,并且下一个插入的行物理上位于表的最后一行,那么将创建一个新页,并把新行添加到新的页上,而不会重新部署现有的数据。在研究索引时,会更深入地讨论页拆分。

3.1.5  行

鉴于你将听到大量关于“行级锁”的说法,因此,对于行这一术语应该不会太意外。通常,行的大小能够达到8KB。

除了行的大小限制为8060字符外,行中的最大列数限制为1024列。实际处理中,在列的大小达到8060字符的限制之前,极少发生列的数目不够用的情况。当为1024列时,平均列的大小为8字节。多数应用中会超出这一大小。关于这一点的例外是在测量和统计信息中——要存储大量不同的数字样本。尽管如此,即便是在这样的应用中,达到1024列的限制也是很罕见的。

你可能已经注意到,在提及8KB的限制时,我使用了“通常”一词。该限制是基于一行限制在一页中,且页的大小为8KB,因而有此限制。但是,在一些情况下可以超出这样的限制——具体地说,是在使用varchar(max)或varbinary(max)以及传统的BLOB数据类型如image和text时。如果行在这些数据类型中的一种中包含的数据过多,无法放置在一页里,那么,这些特殊的数据类型知道如何让数据跨越多个页(一行可以达到2GB)。在这种情况下,原始的行用来记录该列中实际的数据存放在何处(所有其他的列依然存放在原始的行中)。

3.1.6  全文目录

这是位于标准的数据库之外单独的存储机制。虽然能够把全文目录默认关联到指定的数据库上,并且从SQL Server 2005开始,甚至能够与数据库一起备份全文目录,全文目录依然是单独存放的。全文目录的内部结构非常不同,而且,其存储也是由完全不同的服务所管理的(将在第21章中讨论与全文有关的内容)。


字数:5008    最后更新:7个月以前 [04-23 15:33]happyskynet 修改
本页编辑者:happyskynet  
[前一页]:2.7 小结  [后一页]:3.2 理解索引
[在本页中加入书签] [收藏本书] [推荐本书]
  17xie论坛 > 本书讨论区 > 本页评论   (共0条)
发表评论

用户名称 匿名发表
评论内容
验证码

关于我们 | 版权声明 | 免责声明 | 诚聘英才 | 联系我们 | 合作伙伴 | 友情链接 | 广告合作 | 提交意见
Copyright © 2007 17xie.com 互联网协同写书平台 京ICP备08002671号