《SQL Server企业级平台管理实践》读书笔记——SQL Server中收缩数据库不好用的原因
数据库管理员有时候需要控制文件的大小,可能选择收缩文件,或者把某些数据文件情况以便从数据库里删除。
这时候我们就要使用到DBCC SHRINKFILE命令,此命令的脚本为:
DBCC SHRINKFILE
(
{ file_name | file_id }
{ [ , EMPTYFILE ]
| [ [ , target_size ] [ , { NOTRUNCATE | TRUNCATEONLY } ] ]
}
)
[ WITH NO_INFOMSGS ]
由于DBCC SHRINKFILE一次运行会同时影响所有的文件(包括数据文件和日志文件),使用者不能指定每个文件的目标大小,其结果可能不能达到预期的要求。建议是做好规划,对每个文件确定预期目标,然后使用DBCC SHRINKFILE来一个文件一个文件的做比较妥当。
要注意一些几点:
1、首先要了解数据文件当前使用的使用情况。
收缩量的大小不可能超过当前文件的空闲空间的大小。如果想要压缩数据库的大小,首先就要确认数据文件的确有相应未被使用的空间。如果空间都在使用中,那就要先确认大量占用空间的对象,比如:表格或索引,然后通过归档历史数据,先把空间释放出来。
2、主数据文件(primary File)是不能被清空的。能被完全清空的是有辅助数据文件。
3、如果要把一个文件组整个清空,要删除分配在这个文件组上的对象(表格或索引),或者把它们移动到其它文件组上,DBCC SHRINKFILE不会帮你做这个工作。
把数据文件里面该删除的数据和对象清除完、确认数据文件(组)有足够的空闲空间后,管理员就可以下DBCC SHRINKFILE命令来缩小或清空指定文件了。如果是要缩小文件,就填写上要的tearget_size,如果要清空文件,就选择EmptyFile。SQL Server在做DBCC ShrinkFile的时候,会扫描数据文件并对正在读的页面加锁。所以对数据库的性能会有所影响。但是这不是一个独占的行为,也就是说在收缩的时候,其他用户照样可以对数据库进行读写访问。所以不需要单独安排服务器停机时间来做,一般在数据库维护的时候就可以进行。可以在进程中的任意点停止DBCC SHRINKFILE操作,任何已完成的工作都会保留。如果操作没有在规定的时间内完成,也可以完全的停止它。
可是,有时候明明看到数据文件里有空间,为什么就是不能压缩或者情况它呢?这通常是因为数据文件里面虽然有很多空的页面,但是这些页面分散在各个区里,使得整个文件没有很多空的区。
需要说明的是,DBCC SHRINKFILE做的,都是区一级的动作。它会把使用过的区前移,把没有使用中的区从文件中移除。但是,它不会把一个区里面的空页面移除、合并区,也不会在页面里面的空间移除、合并页面。所以,一个数据库中有很多只使用了一两个页面的区,DBCC SHRINKFILE的效果会不明显。
下面的案例来展示这个过程:
我们新建一个每一行都会占用一个页面的表格。表上没有聚集索引,所以是一个堆表。往里面插入8000条数据:
create table show_extent
(
a int,
b nvarchar()
)
go
declare @i int
set @i=
while @i<=
begin
insert into show_extent values(,replicate(N'a',))
insert into show_extent values(,replicate(N'b',))
insert into show_extent values(,replicate(N'c',))
insert into show_extent values(,replicate(N'd',))
insert into show_extent values(,replicate(N'e',))
insert into show_extent values(,replicate(N'f',))
insert into show_extent values(,replicate(N'g',))
insert into show_extent values(,replicate(N'h',))
set @i=@i+
end dbcc showcontig('show_extent')
go

可以看到这个表有1003个区,然后平均每个区里面有8个页面,共计8000个页面...当然这里面包含区碎片所以多处了3个区,24个页的冗余
我们下面删除一部分数据,只保留a=5的这些个记录,来对比前后的空间大小
sp_spaceused show_extent
go
delete show_extent where a<>
go
sp_spaceused show_extent
go
dbcc showcontig('show_extent')
go

可以看到...删除之后的页面空间是没有释放的。只是缩小了一点点。

区没有变化,页数减少了才一半左右,也就是说每个区平均现在只有4.1个页面,在这种情况下去收缩数据库是没有效果的。
我们下面收缩一些看看效果
DBCC SHRINKFILE(,)

可以看到页数不但没有减少,而且增加了..这地方的原因是它按照逻辑分区计算的:1002*8约等于8016..

可以看到能够收缩的空间很少很少..而且给出了一个好的解决方法就是:重新组织页,但是这样会影响性能,也就是说这样它会重新组织页,填充页。
当然我们这里还有另外一个解决方案,通过重建索引的方式把页面重新排列一次。现在还没有聚集索引,我们给他新建一个
create clustered index show_I
on show_extent(a)
go
dbcc showcontig('show_extent')

可以看到...立马缩减到1000页,125个区,我们来看看能收缩多少数据。

现在可以看到了可以收缩的百分比了。我们来执行收缩数据操作

可以看到我们已经将数据收缩至5120,说明此时收缩数据已经产生了作用。
如果不想建立聚集索引,可以把这张表的数据先移走,然后清空表格,再把数据插回来。当然这样比较麻烦,还是有聚集索引管理起来比较方便。
刚才谈到了造成Shrinkfile效果不佳的情况。在一个有聚集索引的的表格上,可以通过重建建立聚集索引来解决。但是如果区里面存放的是text或者image之类的数据类型,SQL Server会单独的页面来存放这些数据。如果这类存储页面也发生同样的问题,和堆一样,做索引重建也不会影响到他们。
对于这种对象的处理方式,就是把这些可能有问题的对象都找出来,然后重新建立他们。可以利用DBCC Extentinfo这个命令打出数据文件里面的所有区的分配信息。然后计算每个对象理论上区的数目和实际数目。如果实际数目远大于理论的数目。那这个对象就是存在多于的碎片,需我们考虑重建对象了。
我们下面来看一个例子:
if exists(select name from sysobjects where NAME ='extentinfo' and type='U')
drop table extentinfo
go
create table extentinfo
( [file_id] smallint,
page_id int,
pg_alloc int,
ext_size int,
obj_id int,
index_id int,
partition_number int,
partition_id bigint,
iam_chain_type varchar(),
pfs_bytes varbinary() )
go
if exists(select name from sysobjects where NAME ='import_extentinfo' and type='P')
drop procedure import_extentinfo
go
create procedure import_extentinfo
as dbcc extentinfo('TestDB')
go
insert extentinfo
exec import_extentinfo
go
select name as table_name,
[file_id],obj_id, index_id, partition_id, ext_size,
'actual page count'=sum(pg_alloc),
'actual extent count'=count(*),
'expected extent count'=ceiling(sum(pg_alloc)*1.0/ext_size), --一个对象的所有盘区页数的各总和/
'expected extents / actual extents' = (ceiling(sum(pg_alloc)*1.00/ext_size)*100.00) / count(*)
from extentinfo inner join sysobjects
on obj_id=id
group by [file_id],obj_id, index_id,partition_id, ext_size ,name
having count(*)-ceiling(sum(pg_alloc)*1.0/ext_size) >
order by partition_id, obj_id, index_id, [file_id]
这里我们通过DBCC extentinfo命令来查看数据库中的区明细,然后查看理论值和实际值的差距,如果存在大量的碎片,我们就需要进行重建清理了。
DBCC EXTENTINFO命令用于查询某个数据库、或者某个数据对象(主要是数据表)的盘区分配情况。其语法结构如下:
DBCC
EXTENTINFO(dbname,tablename,indexid)
我们给出这个命令显示行的明细:
|
字段名称 |
说 明 |
|
file_id |
数据库的数据文件编号 |
|
page_id |
在某个盘区中的第一个页面的页面号 |
|
字段名称 |
说 明 |
|
pg_alloc |
该盘区为数据库分配的页面数量m(1≤m≤8) |
|
ext_size |
盘区的大小,以页面为单位 |
|
object_id |
数据库对象的ID |
|
index_id |
表示数据对象的类型 |
|
partition_number |
分区号 |
|
rows |
大约的数据行数 |
|
hobt_id |
存储数据的堆或B树的存储单元ID |
我们来找个数据库看一下存在碎片的情况:

可以看到上图中,箭头所指的这个行数据,理论应该为一个区就可以,但是实际上它建立了两个分区...所以这种情况可以考虑整理碎片,进行重建,释放碎片。
《SQL Server企业级平台管理实践》读书笔记——SQL Server中收缩数据库不好用的原因的更多相关文章
- 《Microsoft SQL Server企业级平台管理实践》笔记
- 页是 SQL Server 中数据存储的基本单位,大小为 8KB. - 区是空间管理的基本单位,8个物理上连续的页的集合(64KB). - 页的类型包括: 1. Data 2. Index 3. ...
- [读书笔记]SQLSERVER企业级平台管理实践读书笔记01
1. SQLSERVER信息收集 SQLDIAG 使用界面 C:\Users\Administrator>sqldiag2018/01/02 08:13:26.10 SQLDIAG Collec ...
- [读书笔记]SQLSERVER企业级平台管理实践读书笔记02
记录一下 这一块 join的理解了 再完善过来. 1. Statistics的用法: 清空执行计划用的命令 dbcc freeproccache 清空buffer pool 里面的缓存命令 dbcc ...
- 《SQL Server企业级平台管理实践》读书笔记——SQL Server中关于系统库Tempdb总结
Tempdb系统数据库是一个全局资源,可供连接到SQL Server实例的所有用户使用. 存储的内容项: 1.用户对象 用户对象由用户显示创建.这些对象可以位于用户会话的作用域中,也可以位于创建对象所 ...
- 《SQL Server企业级平台管理实践》读书笔记——SQL Server如何设置自动增长和自动收缩项
SQL Server允许用户设置数据库初始值和最大值,可以通过自动增长或者自动收缩进行配置.通过这些配置,我们可以防止数据库空间问题而导致的应用程序修改失败或者SQL Server磁盘空间耗尽的事情发 ...
- 《SQL Server企业级平台管理实践》读书笔记——SQL Server中数据文件空间使用与管理
1.表和索引存储结构 在SQL Server2005以前,一个表格是以一个B树或者一个堆(heap)存放的.每个B树或者堆,在sysindexes里面都有一条记录相对应.SQL Server2005以 ...
- 《SQL Server企业级平台管理实践》读书笔记——关于SQL Server数据库的还原方式
本篇是继上篇的备份方式,本篇介绍的是还原方案,在SQL Server在2005以上现有的还原方案一般分为以下4个级别的数据还原: 1.数据库完整还原级别: 还原和恢复整个数据库.数据库在还原和恢复操作 ...
- 《SQL Server企业级平台管理实践》读书笔记——SQL Server数据库文件分配方式
1.文件分配方式以及文件空间检查方法 最常用的检查数据文件和表大小的命令就是:sp_spaceused 此命令有三个缺陷:1.无法直观的看出每个数据文件和日志文件的使用情况.2.这个存储过程依赖SQL ...
- 《SQL Server企业级平台管理实践》读书笔记——几个系统库的备份与恢复
master数据库 master作为数据库的主要数据库,记录着SQL Server系统的所有系统级信息,例如登录用户.系统配置设置.端点和凭证以及访问其他数据服务器所需要的信息.master数据库还记 ...
随机推荐
- 关于解决JQUERY对INPUT元素Change事件不兼容的问题
最近开发一个项目,需要实现用户在WEB表单里的多个INPUT框中输入数量后,立即自动计算加总各项输入的数量之和,并显示在指定的INPUT框中,这个功能实现的原理是简单的,就是只需要在INPUT的onc ...
- ASP.NET中WebService的两种身份验证方法
一.通过SOAP Header身份验证 此方法是通过设置SOAP Header信息来验证身份,主要通过以下几步: 1.在服务端实现一个SOAP Header类 public class Credent ...
- 【Spark】----Spark on Yarn
最近从Hadoop 1.x 转到Hadoop 2.x 同时将一些java 程序转为Scala的程序将平台上的代码减少了很多,在实施的过程中,开到一些Spark相关的YARN的部署上都是基于之前的Had ...
- 【Unity】13.3 Realtime GI示例
分类:Unity.C#.VS2015 创建日期:2016-04-19 一.简介 使用简单示例而不是使用实际示例的好处是能让你快速理解光照贴图和光影效果相关的概念和基本设置办法,这样可避免实际复杂场景中 ...
- SpreadJS 中应用 KnockoutJS 技术
SpreadJS 支持 Knockout (KO)技术, KnockoutJS 是一个使用 MVVM 模式的 JavaScript 库,允许双向数据绑定,使数据和UI界面进行实时的交互更新.关于KO的 ...
- php中的字符串常用函数(一) strpos() 子字符首次出现的位置
strpos($str, $needle); 1.返回$needle在$str首次出现的位置.(大小写敏感). 2.从php5开始$needle支持多字符.php4只能用单个字符. 3.能找到$nee ...
- NYOJ 42 一笔画问题
一笔画问题 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,判断一个图是否能够用一笔画下 ...
- JAVA书写规范
java程序书写规范 命名规范 1.一般概念 1.尽量使用完整的英文描述符 2.采用适用于相关领域的术语 3.采用大小写混合使名字可读 4 ...
- 趣味问题:画图(c++实现)
描述:在一个定义了直角坐标系的纸上,画一个(x1,y1)到(x2,y2)的矩形指将横坐标范围从x1到x2,纵坐标范围从y1到y2之间的区域涂上颜色.下图给出了一个画了两个矩形的例子.第一个矩形是(1, ...
- ASP.NET MVC中将数据从Controller传递到视图
ASP.NET MVC中将数据从Controller传递到视图方法 1.ViewData ViewData的类型是字典数据,key-value 如:ViewData["Data"] ...