首先谢过进来的高手!
问题如标题所示,先说一下我这里的环境:
PB开发的客户端,使用人数在50人左右,系统很复杂(主要是涉及的功能超级多,如果站在程序员的角度看,其实一点都不复杂),PB版本好像是6.5,不确定。
MS Sql2000做为数据库服务器,数据文件有4G左右,日志文件有3G。
现在的问题是,当客户端从SQL读取一些数据后,查看SQL server(执行sp_lock存储过程),会发现:
这个SPID会在被读取的数据表上,对某一个或几个PAG发出共享锁S
(我们知道,SELECT执行时,其实发出S锁是正常的。但不正常的是:我的客户端明明已经成功读取到了数据了,那么当前SPID为何还保持着S锁不释放?了解SQL server的人都知道,被加上S锁后,其它SPID要等到S锁解除后才能进行更新操作,如果S锁一直保持,那就形成了阻塞,如果永远这样,那就是死锁了。)
进一步研究,我又发现:我的客户端并不是读取所有数据都是这样的。同时,即使是读取同一个数据表,查询条件不同,S锁释放与否也不同。说得更明显一点,读取的数据很多时(比如超过1000条记录),就有可能出现锁定某个PAG不释放的情况。
我用SQL事件探查器追踪客户端执行的SQL语句,然后把相同的语句放到SQL查询分析器里去执行,我发现,无论读取多少数据都不会出现S锁一直保持的情况。那么,问题肯定出在客户端程序内部了。
对于上面的现象,我猜想,是不是客户端程序有一种数据缓冲或者延迟的功能?就好比,客户端向SQL申请读取1000条记录,但它只获取500条记录,其余500条记录它给它加S锁,等到需要要时候再去获取。对于PB,我不是很熟悉,所以无法确定我的理解是否正确,或者还有其它的原因?
另外,客户端源程序我无法看到,所以也无法进一步研究,但我想,如果我上述的猜想成立,那么应该可以设置那个缓冲记录的数量。那么在哪里设置呢?
以上问题,烦请进来的高人能够解答,或者能提供一些解决问题的思路。
无论如何,都谢谢了。
(这个问题,我之前另外有一帖,烦请参考:http://topic.csdn.net/u/20100331/16/b9754dc0-4aa7-48e6-8d21-bcdedb2e9555.html)
------解决方案--------------------
可以用pbkiller反编译你的pb做的exe程序,看看代码也许有帮助
------解决方案--------------------
莫非SQLCA.AutoCommit =true
某程序段UPDATE没COMMIT,在等自动提交?
猜测而已,下班了,好运
------解决方案--------------------
我顶,这个还真不好找!!!
------解决方案--------------------
帮顶1,需要好好研究一下
------解决方案--------------------
sqlca.lock='rc'
------解决方案--------------------
如果 设了SQLCA.AutoCommit =false,执行任何sql语句后,包括datawindow 的相关执行 一定要commit 提交。马上释放掉事务。具体看一下数据库事务的概念,了解清楚sqlca.autocommit这个属性的原理。
------解决方案--------------------
http://topic.csdn.net/t/20040621/16/3110293.html
http://topic.csdn.net/t/20040114/17/2664096.html
看来sql server 的问题可能大些。select 后边也加commit虽然没什么,不过那也要在程序里改啊,你现在程序都看不到也没什么办法。
------解决方案--------------------
http://www.medaili.info/browse.php?u=%20%20Oi8vd3d3LnN5YmFzZWJicy5jb20vc3liYXNlL3JlZGlyZWN0LnBocD90aWQ9Mjg5NCZnb3RvPWxhc3Rwb3N0&b=5
主要是这个:
SQL Server本身对锁处理的问题。说到这里要谈一下锁的“粒度”。SQL Server具有多粒度锁定,允许一个事务锁定不同类型的资源。为了使锁定的成本减至最少,SQL Server自动将资源锁定在适合任务的级别。锁定在较小的粒度(例如行)可以增加并发但需要较大的开销,因为如果锁定了许多行,则需要控制更多的锁。锁定在较大的粒度(例如表)就并发而言是相当昂贵的,因为锁定整个表限制了其它事务对表中任意部分进行访问,但要求的开销较低,因为需要维护的锁较少。按照粒度增加顺序依次为:RID(行标识符)、键、页、扩展盘区、表、DB。一般情况下,使用SQL语句读取数据时(或使用数据窗口的Retrieve方法提取数据),用到的是页级或行级锁。也就是说它读完一页就会释放再读下一页。但如果对一些数据量比较大的表,出现的锁比较多,SQL Server会自动升级为表级锁,对整个表进行锁定。这也没什么问题。关键是在有些情况下(目前不知道是哪个版本解决的),SQL Server会升级表锁而用完不释放!这就会产生问题,遇到这种情况,可考虑给SQL Server打SP4补丁,经试验打上Sp4后不再出现读取数据锁表问题。
前几年老用SQL SERVER,从没遇到过楼主的问题,不过也巧了,我用的都是SP4,不知帖子里讲的对不对。现在改ORALCE了。 楼主自己试试吧
------解决方案--------------------
以前也遇到类似问题,有空聊聊QQ:541446322,初步估计是PB事务控制或者DW取数方法问题
------解决方案--------------------
记住,更改数据后commit;
------解决方案--------------------
以前也遇到过,反复检查程序没发现有不妥之处,甚至执行简单的一条select * from view在遇到特殊数据时也会锁表,后来在微软官网上发现有锁的bug说明,打上补丁就再没出现过问题了,楼主的问题虽然可能是程序问题,但首先应该打补丁后再看。
------解决方案--------------------
搜了下以往的帖子。大致有:
1.数据窗口的Retrieveend事件的脚本中加COMMIT USING SQLCA
http://topic.csdn.net/u/20081120/14/3d6322ba-8832-4eed-b755-a3d96e129468.html
16#说他解决了大面积死锁。
2.select ... from ... with(nolcok)
文档中称:nolock 不要发出共享锁,并且不要提供排它锁。当此选项生效时,可能会读取未提交的事务或一组在读取中间回滚的页面。有可能发生脏读。仅应用于 SELECT 语句。
如果你没源码。估计这个问题解决不了啦。因为你在查询分析器中执行很快完成并未发生锁表现象。那就一定是在程序端了。。。杯具。
------解决方案--------------------
你也需要尝试一下1#的方法,用PBkiller看看代码。6.5的程序估计看个八九不离十。分析一下。如果这种情况只是在很少的地方发生。比如一个窗口中,可以想想办法。比如是只读的,加上nolock。
如果是很早的系统,确实也没源码,甚至找不到开发的人了。而你又确认找到了问题点,可以联系我。帮你直接修改pbd。。(你自己有权利这样做的话)
------解决方案--------------------
这个帖子:
http://topic.csdn.net/u/20081212/00/7666e7f0-9d2c-405e-8a80-92cff9386677.html
9#的网友说得好像很详细,他能提出此问题,想必也是实践过并解决了他自己的问题。。我想你可以参考一下。
虽然无源码。你可以用pb6.5针对模仿你现在的程序做一个dw检索一下。。看看结果。
------解决方案--------------------
打补丁 8.00.760 SQL Server 2000 SP3 !! 类似问题很多年前我遇到过,就是这么解决的。试试吧。
------解决方案--------------------
对不起,没戏看你的版本号,已经SP4了,看来不是补丁的问题。六楼的办法很对。找到源码,加上sqlca.lock='rc',再编译一下,就好了。
------解决方案--------------------
如果只增加sqlca.lock = 'rc'即可解决问题。我可以帮你做手术在pbd文件中增加这一句。如果确实没源码的话。
---------------------------------------------------
PB混淆器(5-12) http://chengg0769.download.csdn.net/
------解决方案--------------------
Windows NT 5.0 (Build 2195: Service Pack 4)
sp4系统和不是sql的sp4吧。
------解决方案--------------------
表行锁改成页锁。
------解决方案--------------------
这种情况,十有八九是autocommit设成了false,然后在某个非select的操作后,没有及时的commit或rollback
我遇到的十次有十次是这个原因,现在都很习惯用false,然后先把commit或rollback写完全上去