IB/FB 事务特性,以及部分误区解释

CuteBit 2004-08-02 09:05:36
加精
引入:
本话题的引入话题是
http://community.csdn.net/Expert/topic/3202/3202674.xml?temp=.830044
里面主要是dbExpress (老枪) 与我的讨论。dbExpress (老枪) 对 FB 的批评过于严厉,自认其不够客观,于是开始了...

假设:
我在下文中假设读者对一些数据库术语的理解.此处我不再细化.

目标:
FB 虽然是开源项目.并不是很多开发员会对它的源码以及框架感兴趣.我们这里讨论 FB 源码中的缺陷没实际意义,这个话题加入FB开发新闻组

讨论更实际,但我不是那个级别的 :(
毕竟对我们这类型的开发员(DB应用开发)来说,注意力是我的系统和功能在 IB/FB 上是否能实现?效率?
至于数据库底层对应用开发员来说只是个白猫黑猫的问题.
所以我这个话题的重点是放在事务数据库原理以及 IB/FB 事务实现上.

正文:
话题的中心是数据库著名的四个保证:
一、原子性 -- 事务的一组更新操作(当然也包括单条 update/insert)的结果只能有两种:全部更新和全部不更新.
对于单条 update/insert 这个不难理解.而对于一组更新它反映在 ANSI-SQL(标准化SQL,被绝大多数数据库所支持的SQL规范)中的

committ work/rollback work 上(ANSI-SQL 并没有 begin transaction,它认为一个事务由系统自行开始.fb/ib 也不是使用SQL开始事务的,很

多商业数据库支持嵌套式事务,都引入 begin transaction [name] 显性开始一个事务,fb1.5 也引入了嵌套事务处理).所以原子性在 ib/fb 里

是有正确实现的.
...全文
484 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
coaco 2005-01-06
  • 打赏
  • 举报
回复
Replicator严格的说不应该是IB原有的功能,是独立于IB一个软件
TR@SOE 2005-01-06
  • 打赏
  • 举报
回复
IB的同步复制功能应该是它提供的Replicator功能吧?

受教不浅。
CuteBit 2004-08-09
  • 打赏
  • 举报
回复
好像有第三方产品实现这个功能。具体你查找看。
其实,也许 ib/fb 里的影子(shadow)功能就是你想要的东西。如果你的 db server 是一台专用的机器,你可以考虑使用现代操作系统的镜像技术来实现。
格利高里 2004-08-09
  • 打赏
  • 举报
回复
好文!up
jingzu 2004-08-09
  • 打赏
  • 举报
回复
IB说有同步复制功能,在“Borlan InterBase7.0应用程序开发指南”说有介绍的,只是简单介绍,没有详细的方法。有谁知道?
jingzu 2004-08-08
  • 打赏
  • 举报
回复
我想使用FB同步复制功能,那里有使用方法?
coaco 2004-08-06
  • 打赏
  • 举报
回复
还想看...
CuteBit 2004-08-04
  • 打赏
  • 举报
回复
hi,dbExpress(老枪)
我喜欢你的认真和钻研,也喜欢你的批评性攻击性。这是技术进步的动力。
我讨论时总是对事不对人的态度,有时用了比较尖锐的词。那不是我的本意。

你的客气礼貌有时让我不知所措。请原谅我的粗鲁。

很高兴能和你讨论一些关于这个的话题。:)
dbExpress 2004-08-04
  • 打赏
  • 举报
回复
尊敬的版主大人,看了您的这张贴子,我深深思考了一晚上,在我收回我对于fb在durable方面的问题的武断之前,我先请您原谅我的无知和愚蠢的傲慢。

我没有认真想过fb的事务清册页的作用,经过您的启发,我才发现事务清册页很有可能就是影子分页法的精妙的变形,如果真的是那样的话,这种技术是非常适合mvcc的。我非常感谢您在技术和学习态度上对我的帮助。

我想我应该仔细阅读一下源码,当然,并不是为了辩论
CuteBit 2004-08-03
  • 打赏
  • 举报
回复
erickleung(),我同意你的看法。系统的商业目标影响设计目标,最终影响实现。
不过这个话题没有 IB/FB vs XXX 的成分。

我只想从原理上肤浅的“解剖”IB/FB。由于文字都是自己写的,也许大家有疑惑或者反对的地方,请加入讨论。
erickleung 2004-08-03
  • 打赏
  • 举报
回复
那是'Apple' 和 '橙'; C和Pascal; basic和asm等的争论.

ib/fb以小巧见称, 随意外挂到各个操作系统上. ib/fb主系统均以Kb单位计算; 但是Oracle/DB2等, 动轧都是Gb为单位. 其自己本身就是个完整的系统. 无论理念, 架构, 市场定位, 都是不同.

因为两者只是按某种需求而产生的一种工具, '以子之矛攻子之盾', 本来就是不能分高下.

能够充份运用其特有的优点和缺点, 才是有意思的讨论.

耙子 2004-08-02
  • 打赏
  • 举报
回复
这东西自认为我没有发言权,可以把TR和唐辉叫来参与一下
CuteBit 2004-08-02
  • 打赏
  • 举报
回复
二、持久性 -- 一旦事务提交,它对数据的修改将是持久的.
为了说明这个问题,需要更深入的说数据库内部的一些东西:页面管理。数据库都是按一定页面分配管理数据库的数据的。出于性能和合理

可配置的利用内存上,它们都采用在内存缓冲一定数量的页面(类似于操作系统管理文件,但它是高层面的)。事务每更新数据,一个或数个

内存页面的数据将被更新,锁方式实现的数据库并不保留每次更新前的记录内容(多版本方式就保留了,这也是多版本的含义),此时考虑到

原则 #1 :需要保证该事务的 rollback 功能,同时其他平行事务的查询等情况,此时锁方式陷入一种"尴尬"的处境,日志就是处理这个问题

的法宝,它记录了记录的更新过程以及事务状态。从某些方面看,多版本数据库简直就是整个日志。格式类似于:
简写:事务1写(W1) 数据项(a,b,...) 数值(50,10,...) 提交(C)
(W1,a,50) C1 (W2,a,10) (W2,b,100)...
在日志中还采用检查点的方法加速数据库愈合过程。IB/FB 记录了记录的每次更新,当用户发出提交指令时它的操作顺序是:
【写数据页面(1..N)】->【写页面分配表(1..N)】->【在事务状态页面标识该事务提交(1)】->【向用户报告成功】
因为【在事务状态页面标识该事务提交(1)】对操作系统来说是个写盘原子操作,所以理论上,只要向用户报告成功就表示数据肯定写盘了。如

果【在事务状态页面标识该事务提交(1)】(我们把这点称为关键点,被认为是一个原子操作)不成功(比如掉电),系统重新启动时,IB/FB

会将这个未完成事务标志成"死"事务而被忽略(即,这个版本的数据是不能使用的)。所以它的愈合是闪电般快速的(当然,它为此付出的代价

是数据库里的那些垃圾空间咯)。这些是理论上的事情,实际编码中没人能完成得这么优美,而这样的 bug 的很难抓到的。理论上数据库对掉

电系统崩溃有很好的愈合力,但是不幸的是所有的数据库都有可能在这时坏掉。
对于较早版本的 ib bug很多,有的bug很严重,能造成数据库损坏。在 IB6 引入了写缓冲的功能,这个功能使用现代操作系统的异步

writefile 实现。它确实给更新频繁的系统带来了性能提高,但是它也带来了一个潜在的危险:此时系统崩溃,磁盘写缓存里的数据将全部丢

失,从而造成数据库数据大量丢失甚至数据库文件损坏。尽管 FB for windows 在些写缓存上做了一些加强:比如,允许设置缓存页面大小以

及时间。在性能与稳定性上你需要进行一个选择,FB 不建议你使用写缓存。实际上 msSQL 的日志文件就是采用非缓冲的直接方式,以增加稳

定性。
为什么有的多版本数据库也使用了日志功能?我们再回头看看上面的那个操作顺序,会发现这样是比较笨的方法,每次都可能会造成多次

IO 操作,在大量修改的事务中这样的效率是很差的。采用合适的日志可以避免多次 IO 而得到性能提升。也有人认为日志同时也会带来更强劲

的数据恢复功能。简洁至上,FB 认为简洁点更符合目前目标。至于 FB 在这方面的发展我以前的回复提到过。

现在我想分析, IB/FB 经常被国内使用者提及掉电会损坏数据库文件情况,或者丢失已经提交的数据。
如果情况如我上面分析的原理一致,这样的情况理论上是不可能的,但不少人还是遇到这个问题?难道代码上还有这么严重的 bug 或者我

们被欺骗了?!
分析如下测试伪代码
#1 -----------------------------------------------------
// 开始一个事务
startTran();
// 在循环中反复插入数据
for(...)
begin
/* ... 做一些事情 ... */

insertTable(); // 插入数据到表中
log(i); // 测试点1,假设 log 是个原子操作而且它的耗时可以忽略
commite(); // 提交事务
log(i); // 测试点2
end;

每次更新数据后立即提交事务,命令数据库永久化所做的修改。
理论上,在这段代码中,系统任何一处崩溃,系统在下次启动时应该看见系统崩溃前的所有提交的数据。如果崩溃点在 commited() 语句

前,当前记录不应该被看见。崩溃点在 commited() 语句后,当前记录应该被看见。崩溃点在 commited() 语句里,当前记录能否被看见,取

决于数据库是否完成关键点。当然这种情况很难在应用层上分析出来,但我们可以估计出这种情况下,未提交的可能性要大得多,因为【在事

务状态页面标识该事务提交(1)】->【向用户报告成功】这两个操作相对前两个是非常短而迅速的。

#2 -----------------------------------------------------
// 开始一个事务
startTran();
// 在循环中反复插入数据
for(...)
begin
/* ... 做一些事情 ... */

insertTable(); // 插入数据到表中
end;
commite(); // 提交事务,或者不需要显性提交事务默认,事务关闭时自动提交

// 或者这样....

// 开始一个事务
startTran();
// 在循环中反复插入数据
for(...)
begin
/* ... 做一些事情 ... */

insertTable(); // 插入数据到表中
if ((i mod 500) == 0)
commite();
end;
commite(); // 提交事务,或者不需要显性提交事务默认,事务关闭时自动提交

批量提交事务,命令数据库永久化所做的修改。
理论上,在这段代码中,系统在关键点前崩溃会丢失当前一批的全部数据。这个很好理解。这种情况下,很有可能使数据库文件出现错误

。因为,在量的更新是数据库中的缓存页面提前写到磁盘数据库文件里。而这里页面因为事务尚未提交,实际上还出于一种“孤独”的状态。

此时系统崩溃会造成这些页面变成废弃泄漏的页面。但这些页面不应该对继续使用这个数据库有影响,应该能被数据库系统检测和处理的。似

乎早期的 IB 对这样我认为属于内部自愈机制没有或者不强,这样的数据库在不使用 gfix 前连备份都不行。有时也会造成数据库不能使用的

情况。我发现 FB1.5 就好得多,它能直接备份还原(这样出来的新数据库是“清洁”的),也能不用任何修复毫无问题的继续使用,这些废弃

的页面会在 IB/FB sweep 里被回收。严格来说第一种情况下有发生这种情况的机会,只是机会较小。所以对 FB 我并不认为这是一个真正的错

误。

ok,以下是我就上述两种情况所做的一个测试:
测试环境【P4-1G/512M RAM/windows2000SP4Professional/FB1.5release(force write on)】
测试内容【按照上述两种情况,分别进行十次的在持续insert逐条提交增加至8000条左右时突然reset计算机】
注意【windows里的磁盘设备写缓冲选项】
结果
【#1 已提交的记录没有丢失,数据库没出现损坏报告】
【#2 已提交的记录没有丢失,丢失当前那批未提交的数据。数据库只有一次没出现损坏报告】

FB 对抗系统崩溃并不像“传说中”那样脆弱。请不要轻易对一个你尚不清楚的事情下结论。众人纷纶中不要迷失自己。

三、一致性 -- 可以将这个特性分两种情况:
1.ANSI-SQL 中的数据完整性一致性参考。如外键约束触发器等,IB/FB 都有很好的实现。
2.用户业务逻辑上的数据一致。这是个不能单独对待的特性。它在逻辑上不是独立的,需要接下来的一个更基本的特性阐述。

四、隔离性 -- 两个并发事务间的相互影象程度。
这里,我不想再深入这个话题。网上有不少文章有。
这个话题引入两个术语:交错读写/可串行化。这是两个对立的概念。理论上,数据库实现采用单一的可串行隔离事务对数据库本身来说是

最“安全”和相对简单的,因为它的原则就是一个事务执行完毕才执行下一个事务。串行化对于某些业务逻辑来说是很重要的。在竞争异常激

烈的数据库大战中,增强数据库的吞吐量是一个非常重要的目标。几乎所有的数据库均采用内核是可交错读写,通过锁机制实现事务的可串行

化的机制(不要老是陷入 IB/FB 多版本控制的误区,实际上在 IB/FB 中同样需要锁机制)。
ANSI-SQL中定义了四个等级事务隔离:read uncommitted/read committed/repeatable read/Serialiable

ANSI-SQL 对事务隔离于 IB/FB 的字面上并不一致,下面是他们的对应关系
ANSI IB/FB
read uncommitted 【未实现】
read committed read_committed | [rec_version/no_rec_version]
repeatable read concurrency(snapshot)
Serialiable consistency

注:很多文章上都是这样认为 repeatable read == concurrency(snapshot),对这个我有怀疑:ANSI定义的repeatable read对记录上长期的

读锁,而concurrency(snapshot)不是。所以我认为它们不是完全相同的。

IB/FB 使用的事务隔离级别我认为是中规中矩的(还有闪光的地方:snapshot这个级别以前只有 oracle 实现了)。合理的运用它们,我

认为能满足绝大部分的数据库应用程序开发。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
好了,罗嗦了一大堆,只想引出一些玉,让 IB/FB 的使用者和爱好者受益。
非常欢迎你的加入 ^_^

2,209

社区成员

发帖
与我相关
我的任务
社区描述
其他数据库开发 其他数据库
社区管理员
  • 其他数据库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧