如何减小数据库的大小?(100分)

  • 主题发起人 主题发起人 herogyf
  • 开始时间 开始时间
H

herogyf

Unregistered / Unconfirmed
GUEST, unregistred user!
请问在dbisam中加入数据记录后(有general字段)执行删除操作,数据库为何不会自动变小?
如果要解决这个问题,有何妙招?望众大侠不惜赐教!!!!
 
一般数据库空间分配后,不能减小,因为他的结构同dbf等文件型数据库不同
 
T-SQL:
DBCC SHRINKDATABASE '数据库名'
 
DBCC SHRINKDATABASE '数据库名' Truncateonly
 
贴一篇文章,请看看:

为Delphi提供Pack和Undelete功能

本文针对Delphi3和Delphi4,对于C++Builder同样也适用,在数据库引擎BDE4.0、4.5、
5.0中经过测试。

Delphi目前已经是国内常见的数据库编程工具,它在各方面表现不错,在支持大型多层数据
库结构的同时也完全支持本地数据库的支持。对于本地数据库中Delphi对FoxPro2.5b的支持
也不错,我曾经对VB、FoxPro2.5b、Delphi的数据库操作速度进行比较,发现除了启动速度
较慢外,其它各项Delphi均排在首位。而且Delphi几乎支持所有原先FoxPro所拥有的功能,
对于有一定编程经验的人来说,Delphi成了编写数据库软件的一把利器,因而Delphi迅速流
行起来,我几年前甚至利用Delphi 1.0和汇编配合制作了工业控制系统的实时前后台软件。

但是在我长期使用Delphi编程的过程中发现它也有不如人意的地方,特别是在本地数据库
FoxPro方面,它居然不支持十分有用的Pack和Undelete功能。对于数据库来说,因为是一个
顺序存储文件,在删除部分记录是一般采用了软删除技术,也就是说将要删除的记录标记已
删除的标记,但并不立即从物理上删除这些记录。这样做可以避免仅仅删除一条记录就要将
整个数据库重新写入存储器,提高了读写的效率。但是如果数据库长期不对已经被标记为删
除的记录进行整理和真实删除,数据库就会越来越大,其中无用的数据所占的比率越来越大
,使得数据库的读写效率迅速下降,而且造成查询速度的减慢。在编写FoxPro数据库时有个
规律,如果数据进出数据库频繁,也就是说不断删除旧的数据,加入新的数据的情况下每次
在关闭数据库的时候或打开数据库的时候先做一次Pack,对数据库进行整理,将软删除的记
录真正从数据库中删除。但是在Delphi的各个版本中数据库控件均未提供Pack的功能,这使
得用Delphi编写的数据库软件如果使用本地数据库的形式,数据库的大小增长很快,即使删
除了大量记录,数据库的大小没有任何改变。以前我的做法是在使用这类数据库软件一段时
间后利用FoxPro打开数据库进行Pack,但是这样做要求客户端拥有FoxPro,而且经常这么做
也很繁。于是我开始查找有关资料,为什么Delphi无法使用pack功能?

经过再三查找,我找到一些资料,说明如何对数据库进行pack了,在将其改编后在Delphi中使用通过。下面是其中的核心程序。

BDE API Call:

DBIResult DBIFN DbiPackTable (hDb, hCursor, pszTableName, [

pszDriverType], bRegenIdxs);

在数据库引擎的底层函数调用中,我找到了这个函数,这个函数据说可以对FoxPro的数据库
进行Pack,其中hDb是数据库的句柄,可以由Table.Handle获得;hCursor是数据表(Table)
关联的游标,如果为NULL则数据表依赖于pszTableName和pszDriverType这两个传输决定数
据库的来源;bRegenIdxs决定是否关联外接的索引文件尤其是MDX多索引文件。

具体的操作函数如下:

procedure PackTable(Table: TTable);

var

Props: CURProps;

hDb: hDBIDb;

begin

if not Table.Active then

raise EDatabaseError.Create('Table必需已经打开');

if not Table.Exclusive then

raise EDatabaseError.Create('Table必需以独占方式打开');

Check(DbiGetCursorProps(Table.Handle, Props));

if (Props.szTableType = szDBASE) then

Check(DbiPackTable(Table.DBHandle, Table.Handle, nil, szDBASE, True))

else

raise EDatabaseError.Create('Table必需是dBASE或FoxPro类型');

Table.Open;

end;

特别对这段源码说明一下,这段源码部分改编自C,已经在上面提到过的环境中测试通过,
需要注意的是,数据表必需以独占方式打开,简单的说,就是在设计时将数据表关闭(属性
Active=False),在运行时才打开数据表(form_onCreate时Table.Open),这样才能保证数
据表在独占方式下被打开。DbiGetCursorProps()是一个读取数据表的属性的底层函数调
用,返回了大部分通用的数据表属性。Check()函数可以简单的处理数据库的出错提示和
异常处理,如果出现函数调用错误会自动显示出错信息。

说了pack那么与之对应的Undelete也就更要解释了,同样我找到了将软删除的数据恢复的函
数,不过这个函数隐藏的更深,连C代码都没有,所以以下的代码完全由我自己摸索出来,
仅在上面说到的环境中测试通过。

首先介绍一下相应的底层函数调用:

DBIResult DBIFN DbiUndeleteRecord (hCursor);

这个函数仅有的参数就是关联的数据表的游标,您可以在BDE.int的文件中找到它的声明,
但是具体的使用说明含糊不清,到底是恢复当前被删记录还是将数据表内所有被软删除的记
录全部恢复?由于缺少相应的代码分析,我参照FoxPro的经验进行了多次实验,在十几种方
案的对比下得出了结论,这条函数调用仅仅恢复当前的被软删除的记录。因此必需首先将数
据表的游标移动到被删除的记录上,然后调用这条函数,才会有所反应。要知道在默认的情
况下,数据库控件是不会将游标移动到被删除的记录上的,所以必需首先将数据表的读写属
性修改,打开软删除的属性,使得遍历数据表时可以访问到被标记为删除的记录。下面是一
段实现将数据表中所有被软删除的记录恢复的源代码。其它形式的反删除可以参照这段代码


procedure Ttablepro.undelete;

var

CProps: CurProps;

rslt: DBIResult;

bm:TBookmark;

rp:pRECProps;

begin

Check(DbiGetCursorProps(self.Handle, CProps));//取得数据表的属性

if (StrIComp(CProps.szTableType, szDBASE) <> 0) then//如果不是Dbase或Foxpro则退出

raise EDBEngineError.Create(DBIERR_NOTSUPPORTED);

rslt:=DbiValidateProp(hDBIObj(self.Handle), curSOFTDELETEON, True);

//可否设置软删除?

if (rslt = DBIERR_NONE) then

Check(DbiSetProp(hDBIObj(self.Handle), curSOFTDELETEON, Longint(true)));

//设置为可以软删除

Check(DbiGetCursorProps(self.Handle, CProps));

//更新数据表的属性

if (CProps.bDeletedOn = False) then

raise EDatabaseError.Create('软删除没有设置!');

//取得当前的记录位置

bm:=self.GetBookmark;

//将游标移动到第一个记录以前!Not Table.First!

Check(DbiSetTobegin(self.handle));

//不断移动,直到到数据表的最后记录

while (DBIGETNEXTRECORD(self.handle,dbinolock,nil,nil)=DBIERR_NONE) do

begin

//请关闭Delphi的异常响应,以便执行下面的语句!

try

check(DbiUndeleteRecord(self.Handle));

except

//Do somthing here !

end;

end;

//取回原先记录的位置,重新定位

self.GotoBookmark(bm);

self.FreeBookmark(bm);

self.Refresh;

end;

(注:如果可以,请在刊登时删去“Self.refresh”一行,对于原理的介绍无需此行,仅在
我的控件的属性中需要,以上代码来自我制作的Delphi控件TTablePro)

在这段代码中已经有了详细的解释,应该可以比较容易的了解undelete的技巧了。当然如果
能够不必与源代码打交道是最好的,因此我制作了一个Delphi的控件TtablePro在Table的基
础上增加了两个方法PackTable和Undelete;包含了上面介绍的功能。您可以到我的主页免费
下载试用,测试版可以免费使用无限制。

如果这篇文章有何问题请与我联络修改。谢谢。另外我可以提供防止应用程序重复加载的技
术文章,同样可以提供相应我制作的免费控件。在任务栏显示图标并直接与弹出式菜单的关
联的控件与完整技术资料,还可以实现动态图标,目前的免费控件仅支持与指定的菜单关联
,就象dataset与datasource一样。我可以提供不少我制作的控件的实现技巧、技术的文章。
另外我可以提供围棋自动提子的算法和技巧的文章,代码来自我制作的自由软件-围棋打谱
软件2.0b…

我的联络地址:Email:mailto:weiwu@kali.com.cn
 
跟楼上想一差不多
 
接受答案了.
 

Similar threads

S
回复
0
查看
752
SUNSTONE的Delphi笔记
S
S
回复
0
查看
759
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
后退
顶部