一个数据库文件不外乎就是一个操作系统文件。针对于数据库文件,sql server有备份策略,逻辑策略是映射成操作系统文件、物理策略例如磁盘驱动器。一个数据库至少分割成两个文件也可以多个。一个是数据文件(例如索引和分配的页),一个是事务日志文件。 数据库文件包含三种类型: 1)关键数据文件。必须有有一个关键数据文件用来存储数据,扩展名为.mdf。 2)第二数据文件。可以有零个或者多个,扩展名为.ndf。 3)日志文件。至少一个日志文件,包含必要的信息用来恢复数据库中的所有事物。扩展名为.ldf。 每个数据库文件包含五个属性 :逻辑文件名、物理文件名、初始大小、最大尺寸、增长值。我们可以通过元数据视图sys.database_files查看这些熟悉,每个文件包含一行数据。例如我创建一个数据库Sample。然后执行在Sample数据库中执行以下sql语句: select * from sys.database_files; 查看到的结果:
关键列说明:
| type | File type: 0 = Rows (includes full-text catalogs upgraded to or created in SQL Server 2008) 1 = Log 2 = FILESTREAM 3 = Reserved for future use 4 = Full-text (includes full-text catalogs from versions earlier than SQL Server 2008) |
| name | The logical name of the fi le |
| physical_name | Operating-system fi le name |
| size | Current size of the fi le, in 8-KB pages. 0 = Not applicable For a database snapshot, size refl ects the maximum space that the snapshot can ever use for the fi le. |
| max_size | Maximum fi le size, in 8-KB pages: 0 = No growth is allowed. –1 = File will grow until the disk is full. 268435456 = Log fi le will grow to a maximum size of 2 terabytes. |
| growth | 0 = File is a fi xed size and will not grow. >0 = File will grow automatically. If is_percent_growth = 0, growth increment is in units of 8-KB pages, rounded to the nearest 64 KB. If is_percent_growth = 1, growth increment is expressed as a whole number percentage. |
创建数据库最简单的方法是使用Management Stdudio对象浏览器创建。它等同于CREATE DATABASE指令。并不是所有的用户都可以创建数据库,创建数据库必须要有相应的权限,具体哪些权限可以创建数据库?包括任何拥有sysadmin角色、任何有CONTROL or ALTER权限、任何有CREATE DATABASE权限的sysadmin或者 dbcreator角色。 当创建了新数据库,SQL Server拷贝model数据库。如果你有一个定制的对象想包含在你创建的新数据库里,你应该首先创建该对象在model数据数据库中。你也可以在model总设置默认数据库参数,新建数据库都会继承这些参数。model数据库包含53个对象:45个系统表、6个对象(用户sql数据)、1张表(帮助管理change tracking)。你可以在 sys.objects查看这些对象,执行sql: select * from sys.objects 可以查看到具体的数据:

一个新的用户数据库不能小于3MB(包括日志文件)。并且主数据文件的大小不能小于model数据库的主数据文件大小。创建数据库时,尽可能地使用默认值创建。因此创建一个数据库的简单sql语句如下:
CREATE DATABASE newdb;
执行该语句后,newdb数据库拥有默认的大小、newdb和newdb_log两个逻辑名称、物理文件newdb.mdf和newdb_log.ldf被创建在默认的文件夹。
接下来给出一个完成的创建数据库语句:
| CREATE DATABASE Archive ON PRIMARY ( NAME = Arch1, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\archdat1.mdf‘, SIZE = 100MB, MAXSIZE = 200MB, FILEGROWTH = 20MB), ( NAME = Arch2, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\archdat2.ndf‘, SIZE = 10GB, MAXSIZE = 50GB, FILEGROWTH = 250MB) LOG ON ( NAME = Archlog1, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\archlog1.ldf‘, SIZE = 2GB, MAXSIZE = 10GB, FILEGROWTH = 100MB); |
你可以为一个数据库分组数据文件到一个“文件分组”里边,它有利于分配和管理。有些时候,你可以通过把数据索引指定到特别的分组从而提升性能。包含主数据文件的分组叫做主文件分组。一个数据库有且仅有一个主文件分组,但你可以通过freelancer关键字创建多个用户定义的分组。 这里必须要说明下主文件分组primary filegroup和主文件的区别: (1)当我们创建一个数据库时,首先看到的就是主文件,一般扩展名为.mdf。主文件一个特殊的功能就是指向master数据库(可通过目录视图sys.database_files查看属于数据库的文件)。 (2)主文件分组包含主文件以及其他没有放置到其他分组的文件。 数据库文件分组有什么用呢?举个简单的例子,你的数据库由一个大小为120G的文件组成,如果你考虑恢复这个数据库,你不得不腾出120G的空间才能恢复整个数据库。但如果我们创建数据库在若干个小文件上,可以增加恢复时的灵活性。 创建FILEGROUP可通过以下指令:
| CREATE DATABASE Sales ON PRIMARY ( NAME = salesPrimary1, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\salesPrimary1.mdf‘, SIZE = 100, MAXSIZE = 500, FILEGROWTH = 100 ), ( NAME = salesPrimary2, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\salesPrimary2.ndf‘, SIZE = 100, MAXSIZE = 500, FILEGROWTH = 100 ), FILEGROUP SalesGroup1 ( NAME = salesGrp1Fi1e1, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\salesGrp1Fi1e1.ndf‘, SIZE = 500, MAXSIZE = 3000, FILEGROWTH = 500 ), ( NAME = salesGrp1Fi1e2, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\salesGrp1Fi1e2.ndf‘, SIZE = 500, MAXSIZE = 3000, FILEGROWTH = 500 ), FILEGROUP SalesGroup2 ( NAME = salesGrp2Fi1e1, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\salesGrp2Fi1e1.ndf‘, SIZE = 100, MAXSIZE = 5000, FILEGROWTH = 500 ), ( NAME = salesGrp2Fi1e2, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\salesGrp2Fi1e2.ndf‘, SIZE = 100, MAXSIZE = 5000, FILEGROWTH = 500 ) LOG ON ( NAME = ‘Sales_log‘, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\saleslog.ldf‘, SIZE = 5MB, MAXSIZE = 25MB, FILEGROWTH = 5MB ); |
当我们想修改文件大小时,可执行: USE master GO ALTER DATABASE Test1 MODIFY FILE ( NAME = ‘test1dat3‘, SIZE = 2000MB); 当我们想添加文件分组并设置为默认时,可参考以下语句:
| ALTER DATABASE Test1 ADD FILEGROUP Test1FG1; GO ALTER DATABASE Test1 ADD FILE ( NAME = ‘test1dat4‘, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\t1dat4.ndf‘, SIZE = 500MB, MAXSIZE = 1000MB, FILEGROWTH = 50MB), ( NAME = ‘test1dat5‘, FILENAME = ‘c:\program files\microsoft sql server\mssql.1\mssql\data\t1dat5.ndf‘, SIZE = 500MB, MAXSIZE = 1000MB, FILEGROWTH = 50MB) TO FILEGROUP Test1FG1; GO ALTER DATABASE Test1 MODIFY FILEGROUP Test1FG1 DEFAULT; GO |
一个数据库由用户创建分配若干空间,用户对象例如表和索引都存储在这些空间里。并且这些空间分配在若干个分割系统文件中。 数据库被分割成许多逻辑页(每个页大小为8KB),每个文件的分页编号也是连续的从0到n,n的大小也是根据文件的大小来定。你可以使用database ID、file ID以及page number区别任何页。当你使用ALTER DATABASE扩展文件时,增加的空间附加在文件的末尾。新分配空间的第一个页便成为n + 1。但你使用 DBCC SHRINKDATABASE或者 DBCC SHRINKFILE缩减数据库时,页编号也是从n到小移除。这样确保了一个文件的页编号总是连续的。 使用CREATE DATABASE创建数据库时,我们可得到一个唯一的database ID,我们可以通过执行以下语句: select * from sys.databases; 查看新增的数据库信息。信息包含name、database_id、create date等等。 设置数据引擎
我们可以在sys.databases目录视图中查看数据库信息: SELECT name, database_id, suser_sname(owner_sid) as owner, create_date, user_access_desc, state_desc FROM sys.databases WHERE database_id <= 4 查询结果如下:

接下来我们讨论一些比较重要的数据库属性
(1)状态属性
| a. SINGLE_USER | RESTRICTED_USER | MULTI_USER | 用来描述用户访问数据库的属性。 例如: ALTER DATABASE Sample SET SINGLE_USER; SINGLE_USER表示某一时刻之允许有一个链接; RESTRICTED_USER表示用户仅仅拥有dbcreator、sysadmin server角色或者是数据库db_owner,才可以访问数据库; MULTI_USER表示任意用户连接。你可以通过SELECT USER_ACCESS_DESC FROM sys.databases WHERE name = ‘<name of database>‘查看数据库用户访问属性。 |
| b. OFFLINE | ONLINE | EMERGENCY | 数据库设置成OFFLINE后该数据库就不能被修改;如果当前有任何用户链接,数据库也不能设置成OFFLINE。 修改语句如下: ALTER DATABASE Sample SET OFFLINE; SELECT state_desc from sys.databases WHERE name = ‘Sample‘; |
| c. READ_ONLY | READ_WRITE | 该组属性设置数据库读写模式,默认是READ_WRITE可读可写,READ_ONLY表示只读,没有INSERT, UPDATE, or DELETE操作。 例如: ALTER DATABASE Sample SET READ_ONLY; SELECT name, is_read_only FROM sys.databases WHERE name = ‘Sample ‘; |
| a. ANSI_NULLS | 如果设置为ON,任何和NULL比较返回UNKNOW;如果设置为OFF,如果两个都是NULL比较结果为TRUE |
首先说说数据库快照的功能:数据库快照可以把数据库镜像到reporting server,你不能读取数据从数据库mirror中。但是你可以创一个mirror的快照然后读取它;形成reports而不需要blocking;协调管理和保护用户错误。 创建快照的语法如下: CREATE DATABASE Sample_snapshot ON (NAME = N‘Sample‘, FILENAME = N‘D:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Sample_snapshot.mdf‘) AS SNAPSHOT OF Sample; 说明:Sample是我们之前创建的Sample数据库逻辑名称,Sample_snapshot.mdf是快照文件。 快照文件仅仅包含数据源中变化的数据,每个快照文件Sql Server会在内存中保持一份位图,标识文件中页的位置,指明是否数据页是否拷贝到快照。只要数据页一旦更新,Sql Server检查文件的位图并确定是否需要拷贝页到快照中。这样的操作叫做copy-on-write。下图展示了一个数据库的快照包含了10%的数据:

当一个进程从快照中读取数据,它首先访问位图确认快照是否包含需要访问页数据。请看下图,我们访问快照,9页数据来源于数据源,一页数据来源于快照。但是通过这种访问形式,不论当前是什么隔离级别,我们访问的数据不会有任何的锁行为。这也是使用快照的一大优势。

必须注意的是,这些位图是存储在缓存中,而不是它自身的文件里边,因此我们需要的时候都能读到它。当数据库重启后,这些位图丢失,需要重新启动构建。
tempdb数据库tempdb和其他数据库最大的一个区别就是当数据库重启后tempdb数据库会被重新创建,它也像其他数据库一样,继承了model数据库的特性。某些数据库选项在tempdb上是无效的,例如OFFLINE以及READONLY。你也不能删除tempdb。 像之前内容,恢复是运行在一个创建了快照的数据库上。我们不能恢复tempdb,因此,我们也不能在tempdb上创建快照。这也意味着,我们不能使用DBCC CHECKDB。 tempdb里边包含三种对象:user objects、internal objects、the version store。下面分别介绍这三种对象: 1)user objects:所有的用户都有权限创建和使用包括在tempdb里边的本地以及全局的临时表。本地和全局临时名是以#或者##号开头。默认情况下,用户是没有权限使用tempdb创建表的,除非这个表以#或者##作为前缀。 2)internal Objects:对于一般的工具,内部对象在tempdb中是不可见的,但是它确实存在于数据库中。它们也没有罗列在catalog view中,因为它们的元数据仅仅存储在内存中。internal objects的三个基础类型分别是:work tables、work files、sort units。当执行一个大的查询、使用XML或者varchar(MAX)、使用statis或者keyset cursors时都会使用work tables;当在查询中使用hash operator、joining、aggregating时会使用work files;当在查询中包含Order by排序时会使用Sort units。Sql Server使用排序构建一个索引,也可能使用排序处理grouping查询。某些joins类型需要Sql Serve线排序数据再执行join。Sort units被创建在tempdb中去处理这些排序的数据。 3)Version Store:The verson store用于支持行级别数据版本技术。 tempdb优化
由于tempdb被使用在许多Sql Server内部操作,所以你不得不去监视和管理它。接下来的部分将讨论它的最佳实践和监视建议。并且将告诉你一些优化让tempdb管理对象更高效。 1)日志优化:像你知道的,影响你数据库的每一个操作都是有日志记录。在tempdb中,却不是这样的。例如,记录更新操作,仅仅原始数据被记录,没有记录新数据。另外,提交操作和提交的日志记录是没有同步到tempdb中,而是同步到其他数据库。 2)分配和缓存优化:许多分配优化被使用到所有数据库,不仅仅tempdb。但是,在操作过程中tempdb中经常有大量的新对象被创建和删除。因此,tempdb的性能冲击比其他的用户数据库都大。在Sql Server 2008中,分配页的访问的高效性决定了有效的自由度;你也看到很少的争夺在分配页方面,相对于之前的版本;Sql Server 2008也提供了一个非常高效的查询算法快速从混合区定位到单个页面。 tempdb的空间监视
Sql Server提供了一些系统视图提供tempdb的报表信息。最简单的是sys.dm_db_file_space_usage,它为每个数据文件返回一行数据。该视图包含的列如下:
| ■ database_id (even though the DBID 2 is the only one used) ■ file_id ■ unallocated_extent_page_count ■ version_store_reserved_page_count ■ user_object_reserved_page_count ■ internal_object_reserved_page_count ■ mixed_extent_page_count |
管理数据库安全
登录名是数据库的拥有者,我们可以在sys.databases视图中查看到SID列,这一列表示登录的SID,并且这个SID拥有这个数据库。数据库的资源被登陆用户所拥有。像你说看到的,数据库的所有对象被数据库Principals拥有。 执行以下语句:
select d.name, d.database_id, p.name
from sys.databases d
inner join sys.server_principals p
on d.owner_sid = p.sid
查看结果:

我们可以查到,master数据库的拥有者为sa登陆名。同时也可以看出数据库中也有一个叫做sa的Principal。
每个数据库都有一个sys.database_principals目录视图,通过这个视图,你可以了解登陆名和数据库中的用户对应关系。下面的查询语句展示了示例数据库中的用户和登陆名的映射关系,也展示了每个数据库用户的默认对象集合schema。
sql语句如下:
select d.name, d.database_id, p.name
from sys.databases d
inner join sys.server_principals p
on d.owner_sid = p.sid
执行结果如下:
)_%60%25g0~%248.png)
分析:登录名sa有用户名称dbo。dbo是一个特殊的登录,dbo被sa登录使用(也被所有的sysadmin角色登录使用,包括在sys.databases罗列的数据库的所有登录)。
数据库和Schemas有什么关系?在ANSI SQL-92标准里,一个schema被定义作为数据库对象的集合,这个集合被单个用户拥有并且在同一个命名空间下。一个命名空间是一些列对象的集合,这个集合中的对象名称是不能重复的。
登录用户(Principals)和Schemas有什么关系?在Sql Server2008,用户和schemas是两个独立的东西。为了理解它们的不同,我们可以认为权限被授予用户(Principals),但对象存放在schemas里边。创建一个新用户一般默认schema都是dbo。
默认的Schemas是怎样的?当你创建一个数据库时,若干schemas包含在数据库中。它们包括dbo、INFORMATION_SCHEMA、guest。另外,每个数据库都有一个叫做sys的schemas,sys提供访问所有的系统表和视图。
移动、拷贝数据库
你可以通过简单的存储过程分离一个数据库,分离时需要保证该数据库没有任何连接。如果存在连接,你可以使用ALTER DATABASE 设置数据库为SINGLE_USER模式中断已存在的连接。一旦分离了数据库,该数据库在sys.databas、system tables中的记录被移除。
分离数据库的指令为:EXEC sp_detach_db <name of database>。例如我们有一个叫做heavi_case2的数据库,我们先执行sql:
select * from sys.databases。结果如下:
jvcd2x.png)
现在我们执行分离数据库指令分离heavi_case2数据库。sql如下:
EXEC sp_detach_db heavi_case2;
然后再查看sys.databases表中的数据。通过结果可以看出heavi_case2已从表中移除。

分离数据库后,我们考虑怎样附件数据库。附件数据库可以使用CREATE DATABASE和FOR
ATTACH选项。语法如下:
CREATE DATABASE database_name
ON <filespec> [ ,...n ]
FOR { ATTACH
| ATTACH_REBUILD_LOG }
需要说明的是,以上语句只需要一个关键文件即可,因为关键文件已经包含了其他文件的位置。但是如果其他文件在不同的路径下就需要附加说明。现在我们根据以上语法把数据库heavi_case2附件到数据库上,在附加之前我们故意把heavi_case2.ldf文件移至其他目录下,然后执行以下语句:
CREATE DATABASE heavi_case2
ON
(NAME = heavi_case2,
FILENAME =
‘C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\heavi_case2.mdf‘
)
FOR ATTACH
查看执行结果:New log file ‘C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\heavi_case2_log.ldf‘ was created.。数据库直接创建了新的日志文件。考虑一种情况:如果我们想拷贝数据库并且日志文件很大时,我们可以不要日志文件,附件数据库时新建日志文件。
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来龙去脉系列之四 数据库和文件
标签: