没办法开发工具版本老,只能用16位的ODBC连接SQL Server7)
在SQL Server7里用sp_who察看,发现死机时有个进程a被进程b
锁住。察看进程b,它的状态又是sleeping。
这个问题让我郁闷死了,那位大虾能够帮助我,先在这里多谢了!
18 个解决方案
#1
关注!
#2
这个问题在SQL SERVER里头叫阻塞,并不是真正的死锁。
原因是由于多方面因素引起的:
1、最主要的原因是SQL SERVER 默认使用的是read commit, 而普通程序使用的加锁级别都是read uncommit. 使用read uncommit(也就是脏读)会影响数据的一致性,但并不是所有的处理都需要加锁。由于你的程序比较旧,所以我考虑没有对需要加锁的事务仔细分析,导致每读数据都要加锁,这个锁会和其他SELECT锁,和UPDATE的更新锁冲突,导致程序彼此等待,尤其是PB的DW,要么不使用事务,要么使用的事务比较长,那么如果有个伙计SELECT了数据不关闭他的DW,而这个DW又处于一个长事务中,其他的人只好等待等待,这样锁越加越多,就只好死机啦。
2、第二个原因与第一个原因类似,但是一般发生在类似代码表这样的表上,因为这类表被频繁访问,因此就形成了处理时候一个非常非常热的点。由于一所说的SELECT锁在这里很容易发生,因此更容易造成阻塞。另外,对于比较小的热点表,SQL SERVER处于性能考虑的原因,在频繁访问的情况下,会自动将行锁升级为表锁。一旦升级为表锁,那么其他访问表的进程就只好死翘翘了。
处理的方法很简单:
1、并不是所有的地方都需要使用read commit的加锁级别,你从application中设置一句sqlca.lock="RU", 使用脏读,这样就可以去掉大多数不必要的SELECT行锁。然后在一定要读最新数据的地方,把SQLCA。LOCK改为RC,用完后再改回来。
这样就避免了几乎80%的阻塞。
2、对于由于行更新,或者其他UPDATE导致的锁,一般数据库会自己协调,在事务比较长的情况下,这需要你对原来的程序做适当的修改。把长事务变为几个小的事务,在事务中做更新操作,不要插入用户的交互。这是系统的设计原则。
如果你的系统对事务的要求不严格,又不想改动原来的程序,办法更简单,在前面
SQLCA。LOCK的基础上,加句SQLCA。AUTOCOMMIT=TRUE,这样每数据修改自动提交,就可以避免大多数由于更新产生的死锁和阻塞。
3、最后要对付的是刚才说的被大量应用频繁访问的表(HOT TABLE),如果你的系统允许使用RU加锁级别,那么不用太考虑,因为SELECT已经不会导致锁定了。
但是如果你不能使用RU方式(1里头提到的办法),
那么要采用这样的手段:
使用索引把更新锁,SELECT锁来分开,同时也避免SQLSERVER傻傻为了性能的原因把行锁升级为表锁。
具体办法是建立一个索引,如果可以的话使用聚集索引,因为聚集索引采用的是类似HASH的检索方式,这样当查找索引的时候,就不需要访问数据表了。
另一种办法,是将你SELECT语句中要检索的数据都加到索引中,例如你检索NAME,SEX,AGE,如果你把三个数据都加入了索引,这就意味着SELECT语句只要找到索引,就已经找到了最后要选取的数据(从索引中),这样自然不会去LOCK表了。这样做的时候要针对你的程序仔细选择索引,否则把索引变成了表的一个备份就没有意义了。
总结一下,就三招:
1、降低加锁级别,2、可能的话使用自动提交 3、采用措施避免表访问的热点
当然,必要的时候优化你的应用程序,仔细划分事务也是很重要的。
OK?
原因是由于多方面因素引起的:
1、最主要的原因是SQL SERVER 默认使用的是read commit, 而普通程序使用的加锁级别都是read uncommit. 使用read uncommit(也就是脏读)会影响数据的一致性,但并不是所有的处理都需要加锁。由于你的程序比较旧,所以我考虑没有对需要加锁的事务仔细分析,导致每读数据都要加锁,这个锁会和其他SELECT锁,和UPDATE的更新锁冲突,导致程序彼此等待,尤其是PB的DW,要么不使用事务,要么使用的事务比较长,那么如果有个伙计SELECT了数据不关闭他的DW,而这个DW又处于一个长事务中,其他的人只好等待等待,这样锁越加越多,就只好死机啦。
2、第二个原因与第一个原因类似,但是一般发生在类似代码表这样的表上,因为这类表被频繁访问,因此就形成了处理时候一个非常非常热的点。由于一所说的SELECT锁在这里很容易发生,因此更容易造成阻塞。另外,对于比较小的热点表,SQL SERVER处于性能考虑的原因,在频繁访问的情况下,会自动将行锁升级为表锁。一旦升级为表锁,那么其他访问表的进程就只好死翘翘了。
处理的方法很简单:
1、并不是所有的地方都需要使用read commit的加锁级别,你从application中设置一句sqlca.lock="RU", 使用脏读,这样就可以去掉大多数不必要的SELECT行锁。然后在一定要读最新数据的地方,把SQLCA。LOCK改为RC,用完后再改回来。
这样就避免了几乎80%的阻塞。
2、对于由于行更新,或者其他UPDATE导致的锁,一般数据库会自己协调,在事务比较长的情况下,这需要你对原来的程序做适当的修改。把长事务变为几个小的事务,在事务中做更新操作,不要插入用户的交互。这是系统的设计原则。
如果你的系统对事务的要求不严格,又不想改动原来的程序,办法更简单,在前面
SQLCA。LOCK的基础上,加句SQLCA。AUTOCOMMIT=TRUE,这样每数据修改自动提交,就可以避免大多数由于更新产生的死锁和阻塞。
3、最后要对付的是刚才说的被大量应用频繁访问的表(HOT TABLE),如果你的系统允许使用RU加锁级别,那么不用太考虑,因为SELECT已经不会导致锁定了。
但是如果你不能使用RU方式(1里头提到的办法),
那么要采用这样的手段:
使用索引把更新锁,SELECT锁来分开,同时也避免SQLSERVER傻傻为了性能的原因把行锁升级为表锁。
具体办法是建立一个索引,如果可以的话使用聚集索引,因为聚集索引采用的是类似HASH的检索方式,这样当查找索引的时候,就不需要访问数据表了。
另一种办法,是将你SELECT语句中要检索的数据都加到索引中,例如你检索NAME,SEX,AGE,如果你把三个数据都加入了索引,这就意味着SELECT语句只要找到索引,就已经找到了最后要选取的数据(从索引中),这样自然不会去LOCK表了。这样做的时候要针对你的程序仔细选择索引,否则把索引变成了表的一个备份就没有意义了。
总结一下,就三招:
1、降低加锁级别,2、可能的话使用自动提交 3、采用措施避免表访问的热点
当然,必要的时候优化你的应用程序,仔细划分事务也是很重要的。
OK?
#3
PS:要知道你的应用总被那个资源缺少锁住,到Enterprise Manager中的MANAGE下观察观察就知道了,然后你就可以又针对性地进行处理了。
GOOK LUCK!
GOOK LUCK!
#4
w102272兄(名字太长了)
您的解释中对于第一个原因我还不太明白,所谓‘SELECT了数据不关闭他的DW,而这个DW又处于一个长事务中’能否具体说明一下。
您的解释中对于第一个原因我还不太明白,所谓‘SELECT了数据不关闭他的DW,而这个DW又处于一个长事务中’能否具体说明一下。
#5
抱歉,这个只是列举个例子,有点口误,说的是:交互与事务应该分开。
因为在PB中很多人喜欢在DATAWINDOWS上做数据的交互(输入和修改),
这样考虑一个RC的加锁级别,必然有些相关表的数据会在使用DW的时候被加锁。
在一般情况下,我们并感觉不到什么。
但是如果程序设计不当,在进入DW交互的窗口前声明了一个事务,由于DW的交互要
占用很长时间(相对计算机),你的事务在一些表上加的锁就会延长很长时间才会被释放。如果LOCK的正好是HOT数据,这种方式就大大增加了由于页锁,行锁导致阻塞其他访问者的机会。(当然这种情况发生得机会很少,但确实有这样的情况。)
至于处理的原则
1、不在事务中包含数据交互和与用户的交互。
2、不在事务中执行大量计算和更新,尽量把耗时计算放在事务外
3、不一定非要采用事务的情况(例如只是更新数据,而不是从银行取款)这类情况,要么每更新提交,要么干脆使用AUTOCOMMIT
因为在PB中很多人喜欢在DATAWINDOWS上做数据的交互(输入和修改),
这样考虑一个RC的加锁级别,必然有些相关表的数据会在使用DW的时候被加锁。
在一般情况下,我们并感觉不到什么。
但是如果程序设计不当,在进入DW交互的窗口前声明了一个事务,由于DW的交互要
占用很长时间(相对计算机),你的事务在一些表上加的锁就会延长很长时间才会被释放。如果LOCK的正好是HOT数据,这种方式就大大增加了由于页锁,行锁导致阻塞其他访问者的机会。(当然这种情况发生得机会很少,但确实有这样的情况。)
至于处理的原则
1、不在事务中包含数据交互和与用户的交互。
2、不在事务中执行大量计算和更新,尽量把耗时计算放在事务外
3、不一定非要采用事务的情况(例如只是更新数据,而不是从银行取款)这类情况,要么每更新提交,要么干脆使用AUTOCOMMIT
#6
w102272 ,谢谢你这么耐心的回复,我决定在我的程序中将SQLCA。AUTOCOMMIT=TRUE ,希望这样可以解决问题,不过想起来,以前在SQL65上似乎没有这个问题,但自从升到70之后,因为PB总是提示:Program type out of range。后来没办法将所有的settrans改为settransobject,也许就是因为这个原因才会这样。希望我可以解决这个问题,因为我的头都被它搞大了,如果真的解决问题,我一定会好好感谢你。不过在这里先谢了。
#7
没有关系,其实我最近也在做PB程序,从SQL ANYWHERE升级到SQL SERVER 7,遇到的问题和你的一模一样。几个用户就锁机器,我都被人找怕了。
后来就LOCK=RU,AUTOCOMMIT=TRUE,再改了改索引,现在再也不死机啦。呵呵。
对于这个问题,似乎lock=RU比 autocommit更有效。
改索引那照,没办法了再用。
good luck!
后来就LOCK=RU,AUTOCOMMIT=TRUE,再改了改索引,现在再也不死机啦。呵呵。
对于这个问题,似乎lock=RU比 autocommit更有效。
改索引那照,没办法了再用。
good luck!
#8
小心使用 AUTOCOMMIT=TRUE !
#9
不过对脏读(Lock = RU)我真的感到有些不放心。w102272你能否分析一下它的
影响。你用过SQL ANYWHERE,熟悉有关Mail复制的东西吗?
影响。你用过SQL ANYWHERE,熟悉有关Mail复制的东西吗?
#10
对于RU,我了解不是太深。勉强说说,希望高手指正。
RU的主要问题,大概就是在RU模式下,另一个用户读到的数据未必是真实数据吧。比如都在RU模式下,一个人提交数据,一个读数据,
如果读的人在前,他就无法看到提交的最新数据,而RC可以保证他在提交后读最新数据。
如果提交在前,读在后,读数据的人不能知道提交数据是否真实,如果数据后来又被更改,他可能读到错误数据,如果提交被事务取消了,他就会读到一些实际不存在的虚假数据(大概叫幻影)吧。
所以如果我们读的数据是代码表(比较固定,很少更新),或者产品目录(不会很频繁变化,或者因为提交很快,这次看不到,下次就看到了,不在意数据可能的变化),就可以使用RU模式。而如果数据更新很频繁,或者在更新数据后频繁被立刻选取,就不建议使用RU,因为这会造成数据在某些时刻的不完全一致。
所以我觉得是否使用RU,主要是考虑业务处理是否容忍数据的轻微改变和不准确?比如做用户订单对产品目录更新,产品目录多一个产品和少一个产品对当前制订单的事情无所谓,就可以使用RU。
而如果是用户保存了一笔钱在帐户上,另一个人在统计总金额,则肯定不能使用RU,在这种业务上使用RU,肯定会造成业务出问题。
至于其他表,比如代码表,一般是很少更新,频繁被读,可以选择适当的时候更新,而平常用RU,可以减少很多HOT表访问的情况,对并发很有好处的。
另外,在数据库系统上,一般人们都倾向于采用雪片模式和星型模式来设计数据库结构。这样如果把数据表划分为关联各种数据的关联表(各种属性表的主键聚集),和保存单个实体的属性表。在属性表上一般都可以使用RU,而在关联表上的读则一定不能使用RU。
对于SQL ANYWHERE的EMAIL复制,我实验过,但是没有成功。这个EMAIL复制是比较特殊的,它允许Sybase 数据库之间通过EMAIL来复制和同步数据。不过现在因为我已经改用了
SQL SERVER了,我感觉SQL SERVER的复制更完善,容易管理使用和可靠。
或许在那种两个SQL ANYWHERE都不能保证在某个同一时刻启动,必须要脱机同步数据的情况下,EMAIL复制才有意义。
另外在SQL SERVER中我看到有一个SQL MAIL的传输服务,不知道是不是这个功能?
反正我现在用SQL SERVER通过TCP的复制很方便,我就不关心EMAIL复制这种形式了。
雪片方式,
RU的主要问题,大概就是在RU模式下,另一个用户读到的数据未必是真实数据吧。比如都在RU模式下,一个人提交数据,一个读数据,
如果读的人在前,他就无法看到提交的最新数据,而RC可以保证他在提交后读最新数据。
如果提交在前,读在后,读数据的人不能知道提交数据是否真实,如果数据后来又被更改,他可能读到错误数据,如果提交被事务取消了,他就会读到一些实际不存在的虚假数据(大概叫幻影)吧。
所以如果我们读的数据是代码表(比较固定,很少更新),或者产品目录(不会很频繁变化,或者因为提交很快,这次看不到,下次就看到了,不在意数据可能的变化),就可以使用RU模式。而如果数据更新很频繁,或者在更新数据后频繁被立刻选取,就不建议使用RU,因为这会造成数据在某些时刻的不完全一致。
所以我觉得是否使用RU,主要是考虑业务处理是否容忍数据的轻微改变和不准确?比如做用户订单对产品目录更新,产品目录多一个产品和少一个产品对当前制订单的事情无所谓,就可以使用RU。
而如果是用户保存了一笔钱在帐户上,另一个人在统计总金额,则肯定不能使用RU,在这种业务上使用RU,肯定会造成业务出问题。
至于其他表,比如代码表,一般是很少更新,频繁被读,可以选择适当的时候更新,而平常用RU,可以减少很多HOT表访问的情况,对并发很有好处的。
另外,在数据库系统上,一般人们都倾向于采用雪片模式和星型模式来设计数据库结构。这样如果把数据表划分为关联各种数据的关联表(各种属性表的主键聚集),和保存单个实体的属性表。在属性表上一般都可以使用RU,而在关联表上的读则一定不能使用RU。
对于SQL ANYWHERE的EMAIL复制,我实验过,但是没有成功。这个EMAIL复制是比较特殊的,它允许Sybase 数据库之间通过EMAIL来复制和同步数据。不过现在因为我已经改用了
SQL SERVER了,我感觉SQL SERVER的复制更完善,容易管理使用和可靠。
或许在那种两个SQL ANYWHERE都不能保证在某个同一时刻启动,必须要脱机同步数据的情况下,EMAIL复制才有意义。
另外在SQL SERVER中我看到有一个SQL MAIL的传输服务,不知道是不是这个功能?
反正我现在用SQL SERVER通过TCP的复制很方便,我就不关心EMAIL复制这种形式了。
雪片方式,
#11
w102272,我已经采用了RU的方式,并且在所有要进行UPDATE的数据窗的UPDATE属性中,选用key and updatable column,如果出现脏读的现象,并且后者作提交,应该会有一个数据窗的错误提示好象是:Change between retrieve and update,大概类似的提示,然后在数据窗的DB ERROR中截获错误信息,改为自己的提示,不知道这样会不会尽可能的避免脏读。我的程序的确有一张HOT TABLE,近乎80%的操作都是针对这张表进行的,可能总是有一个人不停的向表中插入数据,另有几个人修改数据,不过一般情况下是不会出现对同一条记录进行修改,我想应该很少出现脏读的现象。不知道你对我的做法,有没有什么意见。
另外,我发了给mail给你,你收到了吗?
谢谢你的帮助!
另外,我发了给mail给你,你收到了吗?
谢谢你的帮助!
#12
wl02272, 真的很佩服你:你的技术和热心。我现在正在做SQL Server和SQL Anywhere的复制,希望有机会可以在这方面和你交流交流。
#13
别客气。我也只是照书本上说的吹吹。
在DW上做做控制也好。按照你的描述,我倒觉得是不是那张HOT表导致的阻塞?
在插入数据和修改数据的时候,数据库加的都是更新锁,RU对这个没有影响,
我倒是怀疑在其中是否有停顿或者耗时的操作。
至于交流嘛,在CSDN上多多灌水吧。 哈哈。
在DW上做做控制也好。按照你的描述,我倒觉得是不是那张HOT表导致的阻塞?
在插入数据和修改数据的时候,数据库加的都是更新锁,RU对这个没有影响,
我倒是怀疑在其中是否有停顿或者耗时的操作。
至于交流嘛,在CSDN上多多灌水吧。 哈哈。
#14
Sorry.我来谈谈我的看法。
wl02272说的不错,用所提出的办法lock='RU'可以解决l_wind提出的问题,但可能引发新的问题,wl02272自己也谈到了,为什么呢,这得从PB本身谈起。
在数据库应用系统开发中,我们不难发现用VB、Delphi开发的应用程序就不象PB那样经常出现死机,主要原因就在它们对事务处理机制上。
在PB中是隐式自动发出Begin trans,在连接成功、Commit trans、Rollback trans成功后发出,这样就可能出现在发出Begin trans后执行一个大的查询时出现锁升级(对于常用表易出现),一但锁升级就不会自动解除(不光SQL Server其它数据库也一样)。如没有后续处理,试想会出现什么现象,如果用wl02272说的Autocommit=true也能解决,其原理是在执行查询后系统自动发送了Commit trans,但其缺点wl02272已谈过,经过分析我发现了一种更好的方法,就是在数据窗口的retrieveend事件中加入"Rollback;"或"Commit;"其原理与设Autocommit=true一样,但不会影响事务处理。
《Goldenv secret of success》:
在数据窗口的retrieveend事件中加入"Rollback;"或"Commit;"
wl02272说的不错,用所提出的办法lock='RU'可以解决l_wind提出的问题,但可能引发新的问题,wl02272自己也谈到了,为什么呢,这得从PB本身谈起。
在数据库应用系统开发中,我们不难发现用VB、Delphi开发的应用程序就不象PB那样经常出现死机,主要原因就在它们对事务处理机制上。
在PB中是隐式自动发出Begin trans,在连接成功、Commit trans、Rollback trans成功后发出,这样就可能出现在发出Begin trans后执行一个大的查询时出现锁升级(对于常用表易出现),一但锁升级就不会自动解除(不光SQL Server其它数据库也一样)。如没有后续处理,试想会出现什么现象,如果用wl02272说的Autocommit=true也能解决,其原理是在执行查询后系统自动发送了Commit trans,但其缺点wl02272已谈过,经过分析我发现了一种更好的方法,就是在数据窗口的retrieveend事件中加入"Rollback;"或"Commit;"其原理与设Autocommit=true一样,但不会影响事务处理。
《Goldenv secret of success》:
在数据窗口的retrieveend事件中加入"Rollback;"或"Commit;"
#15
我是一个初学数据库的菜鸟,希望与Wonder这样热心我的我交流一下,请给出你的QICQ好吗?我的ICQ是23718582。
#16
如果能根据业务分析一下,把事务序列化,细化,也能够解决这个问题.
而且可以避免脏读引起的可能的数据不一致.
QQ: 16196472
而且可以避免脏读引起的可能的数据不一致.
QQ: 16196472
#17
学习
#1
关注!
#2
这个问题在SQL SERVER里头叫阻塞,并不是真正的死锁。
原因是由于多方面因素引起的:
1、最主要的原因是SQL SERVER 默认使用的是read commit, 而普通程序使用的加锁级别都是read uncommit. 使用read uncommit(也就是脏读)会影响数据的一致性,但并不是所有的处理都需要加锁。由于你的程序比较旧,所以我考虑没有对需要加锁的事务仔细分析,导致每读数据都要加锁,这个锁会和其他SELECT锁,和UPDATE的更新锁冲突,导致程序彼此等待,尤其是PB的DW,要么不使用事务,要么使用的事务比较长,那么如果有个伙计SELECT了数据不关闭他的DW,而这个DW又处于一个长事务中,其他的人只好等待等待,这样锁越加越多,就只好死机啦。
2、第二个原因与第一个原因类似,但是一般发生在类似代码表这样的表上,因为这类表被频繁访问,因此就形成了处理时候一个非常非常热的点。由于一所说的SELECT锁在这里很容易发生,因此更容易造成阻塞。另外,对于比较小的热点表,SQL SERVER处于性能考虑的原因,在频繁访问的情况下,会自动将行锁升级为表锁。一旦升级为表锁,那么其他访问表的进程就只好死翘翘了。
处理的方法很简单:
1、并不是所有的地方都需要使用read commit的加锁级别,你从application中设置一句sqlca.lock="RU", 使用脏读,这样就可以去掉大多数不必要的SELECT行锁。然后在一定要读最新数据的地方,把SQLCA。LOCK改为RC,用完后再改回来。
这样就避免了几乎80%的阻塞。
2、对于由于行更新,或者其他UPDATE导致的锁,一般数据库会自己协调,在事务比较长的情况下,这需要你对原来的程序做适当的修改。把长事务变为几个小的事务,在事务中做更新操作,不要插入用户的交互。这是系统的设计原则。
如果你的系统对事务的要求不严格,又不想改动原来的程序,办法更简单,在前面
SQLCA。LOCK的基础上,加句SQLCA。AUTOCOMMIT=TRUE,这样每数据修改自动提交,就可以避免大多数由于更新产生的死锁和阻塞。
3、最后要对付的是刚才说的被大量应用频繁访问的表(HOT TABLE),如果你的系统允许使用RU加锁级别,那么不用太考虑,因为SELECT已经不会导致锁定了。
但是如果你不能使用RU方式(1里头提到的办法),
那么要采用这样的手段:
使用索引把更新锁,SELECT锁来分开,同时也避免SQLSERVER傻傻为了性能的原因把行锁升级为表锁。
具体办法是建立一个索引,如果可以的话使用聚集索引,因为聚集索引采用的是类似HASH的检索方式,这样当查找索引的时候,就不需要访问数据表了。
另一种办法,是将你SELECT语句中要检索的数据都加到索引中,例如你检索NAME,SEX,AGE,如果你把三个数据都加入了索引,这就意味着SELECT语句只要找到索引,就已经找到了最后要选取的数据(从索引中),这样自然不会去LOCK表了。这样做的时候要针对你的程序仔细选择索引,否则把索引变成了表的一个备份就没有意义了。
总结一下,就三招:
1、降低加锁级别,2、可能的话使用自动提交 3、采用措施避免表访问的热点
当然,必要的时候优化你的应用程序,仔细划分事务也是很重要的。
OK?
原因是由于多方面因素引起的:
1、最主要的原因是SQL SERVER 默认使用的是read commit, 而普通程序使用的加锁级别都是read uncommit. 使用read uncommit(也就是脏读)会影响数据的一致性,但并不是所有的处理都需要加锁。由于你的程序比较旧,所以我考虑没有对需要加锁的事务仔细分析,导致每读数据都要加锁,这个锁会和其他SELECT锁,和UPDATE的更新锁冲突,导致程序彼此等待,尤其是PB的DW,要么不使用事务,要么使用的事务比较长,那么如果有个伙计SELECT了数据不关闭他的DW,而这个DW又处于一个长事务中,其他的人只好等待等待,这样锁越加越多,就只好死机啦。
2、第二个原因与第一个原因类似,但是一般发生在类似代码表这样的表上,因为这类表被频繁访问,因此就形成了处理时候一个非常非常热的点。由于一所说的SELECT锁在这里很容易发生,因此更容易造成阻塞。另外,对于比较小的热点表,SQL SERVER处于性能考虑的原因,在频繁访问的情况下,会自动将行锁升级为表锁。一旦升级为表锁,那么其他访问表的进程就只好死翘翘了。
处理的方法很简单:
1、并不是所有的地方都需要使用read commit的加锁级别,你从application中设置一句sqlca.lock="RU", 使用脏读,这样就可以去掉大多数不必要的SELECT行锁。然后在一定要读最新数据的地方,把SQLCA。LOCK改为RC,用完后再改回来。
这样就避免了几乎80%的阻塞。
2、对于由于行更新,或者其他UPDATE导致的锁,一般数据库会自己协调,在事务比较长的情况下,这需要你对原来的程序做适当的修改。把长事务变为几个小的事务,在事务中做更新操作,不要插入用户的交互。这是系统的设计原则。
如果你的系统对事务的要求不严格,又不想改动原来的程序,办法更简单,在前面
SQLCA。LOCK的基础上,加句SQLCA。AUTOCOMMIT=TRUE,这样每数据修改自动提交,就可以避免大多数由于更新产生的死锁和阻塞。
3、最后要对付的是刚才说的被大量应用频繁访问的表(HOT TABLE),如果你的系统允许使用RU加锁级别,那么不用太考虑,因为SELECT已经不会导致锁定了。
但是如果你不能使用RU方式(1里头提到的办法),
那么要采用这样的手段:
使用索引把更新锁,SELECT锁来分开,同时也避免SQLSERVER傻傻为了性能的原因把行锁升级为表锁。
具体办法是建立一个索引,如果可以的话使用聚集索引,因为聚集索引采用的是类似HASH的检索方式,这样当查找索引的时候,就不需要访问数据表了。
另一种办法,是将你SELECT语句中要检索的数据都加到索引中,例如你检索NAME,SEX,AGE,如果你把三个数据都加入了索引,这就意味着SELECT语句只要找到索引,就已经找到了最后要选取的数据(从索引中),这样自然不会去LOCK表了。这样做的时候要针对你的程序仔细选择索引,否则把索引变成了表的一个备份就没有意义了。
总结一下,就三招:
1、降低加锁级别,2、可能的话使用自动提交 3、采用措施避免表访问的热点
当然,必要的时候优化你的应用程序,仔细划分事务也是很重要的。
OK?
#3
PS:要知道你的应用总被那个资源缺少锁住,到Enterprise Manager中的MANAGE下观察观察就知道了,然后你就可以又针对性地进行处理了。
GOOK LUCK!
GOOK LUCK!
#4
w102272兄(名字太长了)
您的解释中对于第一个原因我还不太明白,所谓‘SELECT了数据不关闭他的DW,而这个DW又处于一个长事务中’能否具体说明一下。
您的解释中对于第一个原因我还不太明白,所谓‘SELECT了数据不关闭他的DW,而这个DW又处于一个长事务中’能否具体说明一下。
#5
抱歉,这个只是列举个例子,有点口误,说的是:交互与事务应该分开。
因为在PB中很多人喜欢在DATAWINDOWS上做数据的交互(输入和修改),
这样考虑一个RC的加锁级别,必然有些相关表的数据会在使用DW的时候被加锁。
在一般情况下,我们并感觉不到什么。
但是如果程序设计不当,在进入DW交互的窗口前声明了一个事务,由于DW的交互要
占用很长时间(相对计算机),你的事务在一些表上加的锁就会延长很长时间才会被释放。如果LOCK的正好是HOT数据,这种方式就大大增加了由于页锁,行锁导致阻塞其他访问者的机会。(当然这种情况发生得机会很少,但确实有这样的情况。)
至于处理的原则
1、不在事务中包含数据交互和与用户的交互。
2、不在事务中执行大量计算和更新,尽量把耗时计算放在事务外
3、不一定非要采用事务的情况(例如只是更新数据,而不是从银行取款)这类情况,要么每更新提交,要么干脆使用AUTOCOMMIT
因为在PB中很多人喜欢在DATAWINDOWS上做数据的交互(输入和修改),
这样考虑一个RC的加锁级别,必然有些相关表的数据会在使用DW的时候被加锁。
在一般情况下,我们并感觉不到什么。
但是如果程序设计不当,在进入DW交互的窗口前声明了一个事务,由于DW的交互要
占用很长时间(相对计算机),你的事务在一些表上加的锁就会延长很长时间才会被释放。如果LOCK的正好是HOT数据,这种方式就大大增加了由于页锁,行锁导致阻塞其他访问者的机会。(当然这种情况发生得机会很少,但确实有这样的情况。)
至于处理的原则
1、不在事务中包含数据交互和与用户的交互。
2、不在事务中执行大量计算和更新,尽量把耗时计算放在事务外
3、不一定非要采用事务的情况(例如只是更新数据,而不是从银行取款)这类情况,要么每更新提交,要么干脆使用AUTOCOMMIT
#6
w102272 ,谢谢你这么耐心的回复,我决定在我的程序中将SQLCA。AUTOCOMMIT=TRUE ,希望这样可以解决问题,不过想起来,以前在SQL65上似乎没有这个问题,但自从升到70之后,因为PB总是提示:Program type out of range。后来没办法将所有的settrans改为settransobject,也许就是因为这个原因才会这样。希望我可以解决这个问题,因为我的头都被它搞大了,如果真的解决问题,我一定会好好感谢你。不过在这里先谢了。
#7
没有关系,其实我最近也在做PB程序,从SQL ANYWHERE升级到SQL SERVER 7,遇到的问题和你的一模一样。几个用户就锁机器,我都被人找怕了。
后来就LOCK=RU,AUTOCOMMIT=TRUE,再改了改索引,现在再也不死机啦。呵呵。
对于这个问题,似乎lock=RU比 autocommit更有效。
改索引那照,没办法了再用。
good luck!
后来就LOCK=RU,AUTOCOMMIT=TRUE,再改了改索引,现在再也不死机啦。呵呵。
对于这个问题,似乎lock=RU比 autocommit更有效。
改索引那照,没办法了再用。
good luck!
#8
小心使用 AUTOCOMMIT=TRUE !
#9
不过对脏读(Lock = RU)我真的感到有些不放心。w102272你能否分析一下它的
影响。你用过SQL ANYWHERE,熟悉有关Mail复制的东西吗?
影响。你用过SQL ANYWHERE,熟悉有关Mail复制的东西吗?
#10
对于RU,我了解不是太深。勉强说说,希望高手指正。
RU的主要问题,大概就是在RU模式下,另一个用户读到的数据未必是真实数据吧。比如都在RU模式下,一个人提交数据,一个读数据,
如果读的人在前,他就无法看到提交的最新数据,而RC可以保证他在提交后读最新数据。
如果提交在前,读在后,读数据的人不能知道提交数据是否真实,如果数据后来又被更改,他可能读到错误数据,如果提交被事务取消了,他就会读到一些实际不存在的虚假数据(大概叫幻影)吧。
所以如果我们读的数据是代码表(比较固定,很少更新),或者产品目录(不会很频繁变化,或者因为提交很快,这次看不到,下次就看到了,不在意数据可能的变化),就可以使用RU模式。而如果数据更新很频繁,或者在更新数据后频繁被立刻选取,就不建议使用RU,因为这会造成数据在某些时刻的不完全一致。
所以我觉得是否使用RU,主要是考虑业务处理是否容忍数据的轻微改变和不准确?比如做用户订单对产品目录更新,产品目录多一个产品和少一个产品对当前制订单的事情无所谓,就可以使用RU。
而如果是用户保存了一笔钱在帐户上,另一个人在统计总金额,则肯定不能使用RU,在这种业务上使用RU,肯定会造成业务出问题。
至于其他表,比如代码表,一般是很少更新,频繁被读,可以选择适当的时候更新,而平常用RU,可以减少很多HOT表访问的情况,对并发很有好处的。
另外,在数据库系统上,一般人们都倾向于采用雪片模式和星型模式来设计数据库结构。这样如果把数据表划分为关联各种数据的关联表(各种属性表的主键聚集),和保存单个实体的属性表。在属性表上一般都可以使用RU,而在关联表上的读则一定不能使用RU。
对于SQL ANYWHERE的EMAIL复制,我实验过,但是没有成功。这个EMAIL复制是比较特殊的,它允许Sybase 数据库之间通过EMAIL来复制和同步数据。不过现在因为我已经改用了
SQL SERVER了,我感觉SQL SERVER的复制更完善,容易管理使用和可靠。
或许在那种两个SQL ANYWHERE都不能保证在某个同一时刻启动,必须要脱机同步数据的情况下,EMAIL复制才有意义。
另外在SQL SERVER中我看到有一个SQL MAIL的传输服务,不知道是不是这个功能?
反正我现在用SQL SERVER通过TCP的复制很方便,我就不关心EMAIL复制这种形式了。
雪片方式,
RU的主要问题,大概就是在RU模式下,另一个用户读到的数据未必是真实数据吧。比如都在RU模式下,一个人提交数据,一个读数据,
如果读的人在前,他就无法看到提交的最新数据,而RC可以保证他在提交后读最新数据。
如果提交在前,读在后,读数据的人不能知道提交数据是否真实,如果数据后来又被更改,他可能读到错误数据,如果提交被事务取消了,他就会读到一些实际不存在的虚假数据(大概叫幻影)吧。
所以如果我们读的数据是代码表(比较固定,很少更新),或者产品目录(不会很频繁变化,或者因为提交很快,这次看不到,下次就看到了,不在意数据可能的变化),就可以使用RU模式。而如果数据更新很频繁,或者在更新数据后频繁被立刻选取,就不建议使用RU,因为这会造成数据在某些时刻的不完全一致。
所以我觉得是否使用RU,主要是考虑业务处理是否容忍数据的轻微改变和不准确?比如做用户订单对产品目录更新,产品目录多一个产品和少一个产品对当前制订单的事情无所谓,就可以使用RU。
而如果是用户保存了一笔钱在帐户上,另一个人在统计总金额,则肯定不能使用RU,在这种业务上使用RU,肯定会造成业务出问题。
至于其他表,比如代码表,一般是很少更新,频繁被读,可以选择适当的时候更新,而平常用RU,可以减少很多HOT表访问的情况,对并发很有好处的。
另外,在数据库系统上,一般人们都倾向于采用雪片模式和星型模式来设计数据库结构。这样如果把数据表划分为关联各种数据的关联表(各种属性表的主键聚集),和保存单个实体的属性表。在属性表上一般都可以使用RU,而在关联表上的读则一定不能使用RU。
对于SQL ANYWHERE的EMAIL复制,我实验过,但是没有成功。这个EMAIL复制是比较特殊的,它允许Sybase 数据库之间通过EMAIL来复制和同步数据。不过现在因为我已经改用了
SQL SERVER了,我感觉SQL SERVER的复制更完善,容易管理使用和可靠。
或许在那种两个SQL ANYWHERE都不能保证在某个同一时刻启动,必须要脱机同步数据的情况下,EMAIL复制才有意义。
另外在SQL SERVER中我看到有一个SQL MAIL的传输服务,不知道是不是这个功能?
反正我现在用SQL SERVER通过TCP的复制很方便,我就不关心EMAIL复制这种形式了。
雪片方式,
#11
w102272,我已经采用了RU的方式,并且在所有要进行UPDATE的数据窗的UPDATE属性中,选用key and updatable column,如果出现脏读的现象,并且后者作提交,应该会有一个数据窗的错误提示好象是:Change between retrieve and update,大概类似的提示,然后在数据窗的DB ERROR中截获错误信息,改为自己的提示,不知道这样会不会尽可能的避免脏读。我的程序的确有一张HOT TABLE,近乎80%的操作都是针对这张表进行的,可能总是有一个人不停的向表中插入数据,另有几个人修改数据,不过一般情况下是不会出现对同一条记录进行修改,我想应该很少出现脏读的现象。不知道你对我的做法,有没有什么意见。
另外,我发了给mail给你,你收到了吗?
谢谢你的帮助!
另外,我发了给mail给你,你收到了吗?
谢谢你的帮助!
#12
wl02272, 真的很佩服你:你的技术和热心。我现在正在做SQL Server和SQL Anywhere的复制,希望有机会可以在这方面和你交流交流。
#13
别客气。我也只是照书本上说的吹吹。
在DW上做做控制也好。按照你的描述,我倒觉得是不是那张HOT表导致的阻塞?
在插入数据和修改数据的时候,数据库加的都是更新锁,RU对这个没有影响,
我倒是怀疑在其中是否有停顿或者耗时的操作。
至于交流嘛,在CSDN上多多灌水吧。 哈哈。
在DW上做做控制也好。按照你的描述,我倒觉得是不是那张HOT表导致的阻塞?
在插入数据和修改数据的时候,数据库加的都是更新锁,RU对这个没有影响,
我倒是怀疑在其中是否有停顿或者耗时的操作。
至于交流嘛,在CSDN上多多灌水吧。 哈哈。
#14
Sorry.我来谈谈我的看法。
wl02272说的不错,用所提出的办法lock='RU'可以解决l_wind提出的问题,但可能引发新的问题,wl02272自己也谈到了,为什么呢,这得从PB本身谈起。
在数据库应用系统开发中,我们不难发现用VB、Delphi开发的应用程序就不象PB那样经常出现死机,主要原因就在它们对事务处理机制上。
在PB中是隐式自动发出Begin trans,在连接成功、Commit trans、Rollback trans成功后发出,这样就可能出现在发出Begin trans后执行一个大的查询时出现锁升级(对于常用表易出现),一但锁升级就不会自动解除(不光SQL Server其它数据库也一样)。如没有后续处理,试想会出现什么现象,如果用wl02272说的Autocommit=true也能解决,其原理是在执行查询后系统自动发送了Commit trans,但其缺点wl02272已谈过,经过分析我发现了一种更好的方法,就是在数据窗口的retrieveend事件中加入"Rollback;"或"Commit;"其原理与设Autocommit=true一样,但不会影响事务处理。
《Goldenv secret of success》:
在数据窗口的retrieveend事件中加入"Rollback;"或"Commit;"
wl02272说的不错,用所提出的办法lock='RU'可以解决l_wind提出的问题,但可能引发新的问题,wl02272自己也谈到了,为什么呢,这得从PB本身谈起。
在数据库应用系统开发中,我们不难发现用VB、Delphi开发的应用程序就不象PB那样经常出现死机,主要原因就在它们对事务处理机制上。
在PB中是隐式自动发出Begin trans,在连接成功、Commit trans、Rollback trans成功后发出,这样就可能出现在发出Begin trans后执行一个大的查询时出现锁升级(对于常用表易出现),一但锁升级就不会自动解除(不光SQL Server其它数据库也一样)。如没有后续处理,试想会出现什么现象,如果用wl02272说的Autocommit=true也能解决,其原理是在执行查询后系统自动发送了Commit trans,但其缺点wl02272已谈过,经过分析我发现了一种更好的方法,就是在数据窗口的retrieveend事件中加入"Rollback;"或"Commit;"其原理与设Autocommit=true一样,但不会影响事务处理。
《Goldenv secret of success》:
在数据窗口的retrieveend事件中加入"Rollback;"或"Commit;"
#15
我是一个初学数据库的菜鸟,希望与Wonder这样热心我的我交流一下,请给出你的QICQ好吗?我的ICQ是23718582。
#16
如果能根据业务分析一下,把事务序列化,细化,也能够解决这个问题.
而且可以避免脏读引起的可能的数据不一致.
QQ: 16196472
而且可以避免脏读引起的可能的数据不一致.
QQ: 16196472
#17
学习