sql 存储过程 锁,进程死锁
一、SQL***进程死锁
首先,需要把你的AutoCommit=TRUE,然后,这是一个编程习惯问题,在pb中,对于数据窗口的操作,首先设置数据窗口的提交方式,我一直
采用 key columns,use
update,然后记得在每次连接完成后,记得及时释放,譬如,在retrieve完成后,记得及时利用resetupdate()清除数据状态,然后,
再每次数据库更新,也就是update()后,记得利用
ll_num1=.update()
if ll_num=1 then
commit;
dw_free.resetupdate()
else
rollback;
messagebox("提示!","数据保存失败!")
end if
以上说法我不赞同:
1、首先AutoCommit=TRUE,以后执行delete,update,insert语句都相当执行了commit,如果是把几个SQL语句当作是一个完整的事务,要不整
体成功提交,要不rollback,这就写就不会得到正确的结果。
2、其次key columns,use update,要具体情况具体使用,这种形式的并发性最差,适合对数据的并发性要求不高的场合。
3、再次程序的死锁原因是多方面的,上述两个方面只是其中的原因罢了,具体情况具体分析,例如数据尽快提交、建立合理的索引、合理的SQ
L语句、避免交叉事务、对于数据量庞大的表,应及时转移到历史库,我想可以很大程度上避免死锁。
以上愚见,欢迎拍砖。
在MSSQL控制台中,管理-当前活动-锁/进程ID看看是那几个进程在死锁,然后在进程信息中将这些死锁的进程杀死/
对查询进行优化
也建议检查:外键建立索引,如果上索引,再调试下网络
对外键建索引可以缓解这个问题。
如在商品字典和销售明细表中,销售明细表中商品编号是外键,如果在销售明细表的商品编号上没有索引,update商品字典会造成销售明细表
整表锁表。
解决Sybase数据库死锁的方法
人民银行吉林市中心支行科技处刘志明
在联机事务处理(OLTP)的数据库应用系统中,多用户、多任务的并发性是系统最重要的技术指标之一。为了提高并发性,目前大部分RDBMS都采
用加锁技术。然而由于现实环境的复杂性,使用加锁技术又不可避免地产生了死锁问题。因此如何合理有效地使用加锁技术,最小化死锁是开
发联机事务处理系统的关键。
死锁产生的原因
在联机事务处理系统中,造成死机主要有两方面原因。一方面,由于多用户、多任务的并发性和事务的完整性要求,当多个事务处理对多个资
源同时访问时,若双方已锁定一部分资源但也都需要对方已锁定的资源时,无法在有限的时间内完全获得所需的资源,就会处于无限的等待状
态,从而造成其对资源需求的死锁。
另一方面,数据库本身加锁机制的实现方法不同,各数据库系统也会产生其特殊的死锁情况。如在Sybase SQL Server 11中,最小锁为2K一页
的加锁方法,而非行级锁。如果某张表的记录数少且记录的长度较短(即记录密度高,如应用系统中的系统配置表或系统参数表就属于此类表)
,被访问的频率高,就容易在该页上产生死锁。
几种死锁情况及解决方法
清算应用系统中,容易发生死锁的几种情况如下:
●不同的存储过程、触发器、动态SQL语句段按照不同的顺序同时访问多张表;
●在交换期间添加记录频繁的表,但在该表上使用了非群集索引(non-clustered);
●表中的记录少,且单条记录较短,被访问的频率较高;
●整张表被访问的频率高(如代码对照表的查询等)。
以上死锁情况的对应处理方法如下:
●在系统实现时应规定所有存储过程、触发器、动态SQL语句段中,对多张表的操作总是使用同一顺序。如:有两个存储过程proc1、proc2,
都需要访问三张表zltab、z2tab和z3tab,如果proc1按照zltab、z2tab和z3tab的顺序进行访问,那么,proc2也应该按照以上顺序访问这三张
表。
●对在交换期间添加记录频繁的表,使用群集索引(clustered),以减少多个用户添加记录到该表的最后一页上,在表尾产生热点,造成死锁
。这类表多为往来账的流水表,其特点是在交换期间需要在表尾追加大量的记录,并且对已添加的记录不做或较少做删除操作。
●对单张表中记录数不太多,且在交换期间select或updata较频繁的表可使用设置每页最大行的办法,减少数据在表中存放的密度,模拟行级
锁,减少在该表上死锁情况的发生。这类表多为信息繁杂且记录条数少的表。
如:系统配置表或系统参数表。在定义该表时添加如下语句:
with max_rows_per_page=1
●在存储过程、触发器、动态SQL语句段中,若对某些整张表select操作较频繁,则可能在该表上与其他访问该表的用户产生死锁。对于检查
账号是否存在,但被检查的字段在检查期间不会被更新等非关键语句,可以采用在select命令中使用at isolation read uncommitted子句的方
法解决。该方法实际上降低了select语句对整张表的锁级别,提高了其他用户对该表操作的并发性。在系统高负荷运行时,该方法的效果尤为
显著。
例如:
select*from titles at isolation read uncommitted
●对流水号一类的顺序数生成器字段,可以先执行updata流水号字段+1,然后再执行select获取流水号的方法进行操作。
小结
笔者对同城清算系统进行压力测试时,分别对采用上述优化方法和不采用优化方法的两套系统进行测试。在其他条件相同的情况下,相同业务
笔数、相同时间内,死锁发生的情况如下:
采用优化方法的系统: 0次/万笔业务;
不采用优化方法的系统:50~200次/万笔业务。
所以,使用上述优化方法后,特别是在系统高负荷运行时效果尤为显著。总之,在设计、开发数据库应用系统,尤其是OLTP系统时,应该根据
应用系统的具体情况,依据上述原则对系统分别优化,为开发一套高效、可靠的应用系统打下良好的基础。
经验:
1:前台问题:检视代码查看事物是否被提交或回滚。
2:后台问题:有时候由于处理的问题复杂度高。数据库日志空间已满或不够
导致事物未能提交。UNIX下的SYBAE就是典型的一例。解决办法各数据库厂商有更详细的说明。
虽然我从9转到10遇到了好多问题,也浪费了好几天的时间,但到了现在,我真觉得10比9好。
10没有了MSSQL专用接口,用的是OLEDB接口,用这个接口一定要注意一个问题是表死锁的事!
网上讲的连接方式都是天下一大抄。
用OLEDB要加上 SQLCA.Lock="RC",
不然连查询也会死锁。
另个一个就是10写的软件不再乱码了,我在繁体写的软件在简体下运行不乱码,反之也可以。
第三就是编译速度明显快很多。
第四就是编译的时候有了XP样式皮肤,感觉漂亮多了。
编程要是要养成好习惯,在sql语句insert和update之后,要及时commit,数据窗口update()后也要及时commit;
阻塞是因为多个进程对同一一个资源的访问冲突,当一个进程排它访问一个资源时(从进入事务到事务结束为止),当有其他进程需要访问同
样的资源时,即造成阻塞(根据锁的级别和粒度设置);
在实际应用中阻塞可能因为事务没有提交或者网络速度太慢或者大容量的数据查询等都可能会造成阻塞。
阻塞可以通过sp_who系统存储过程进行查看,执行sp_who后查看所有blk不等于
0的进程ID(SPID),直到找到SPID在blk列出现,但当前spid的blk列=0即它就是阻塞的源头。
最简单的办法可用 kill spid(源头进程的SPID值),同时结合sp_lock过程可查看到当前进程的加锁情况(如锁的类型被锁的对象)
最后最重要的是要根据在查询到源头后,使用 DBCC INPUTBUFFER(spid)查看最后一次提交的内容,即可找到因为事务没有提交造成的阻塞(
一般不能使用 AutoCommit=True,因为大部分MIS程序需要使用批提交,来保证数据的完成性)
你可能平时编程时没有注意。在 SQLCA(Transaction)默认情况下 AutoCommit= false(不自动提交)。在同一事务中,如果不提交事务,
可以SELECT、Retrieve,但其它事务(其它计算机的应用程序连接数据库的事务)就不能。所以导致死锁,而在单机开发环境看不出来。
你需要在所有的 UPDATE、DELETE的SQL语句后面,或者数据窗口的Update函数调用之后执行 COMMIT或 ROLLBACK
死锁可能存在的原因及解决办法
一次偶然的机会在论坛上看到一个关于死锁(其实是阻塞)的帖子,于是把自己的一个小东东拿出来和大家分享,想不到很多人都遇到过这个
问题。
其实解锁并不是根本的解决办法,感觉我自己有点误导大家了,于是有了下面的内容,希望大家能根据自己的应用找出根源,而不是解锁:
阻塞可能存在的原因及解决方法:
1、事务未提交
这是造成阻塞最常见的原因,因为PB默认是自动启动事务的,如果你执行了 update,delete,insert语句,不执行Commit则会出现阻塞(
不建议采用自动提交事务的方式,原因在上一帖中交代过),解决的办法很简单,查找到所有的修改数据命令(U、I、D)查看是否正常提交,找
到后加入Commit即可;
2、SQL SERVER没有正常安装SP3
对于代码正常的用户,仍然出现阻塞,则需要检查你机器的补丁,特别是WIN2003的机器不安装补丁,1433都不能监听;如果没有安装补丁
即可(我原来就是被这种情况害过)
3、当然可能你会告诉我,代码也没有问题,补丁也装了,仍然出现可能就需要查看你的机器的CPU和内存的使用率(运行taskmgr),SQL
SERVER的机器峰值状态可能出现阻塞,解决的办法就是出钱:升级服务器;
4、复杂的查询或者大容量查询,比如在查询中使用多个表的联合查询,或者使用 in,not in等语句,是非常耗时的,这种解决的办法稍微复
杂点,需要根据你的应用修改SQL语句,优化SQL效率,关于SQL优化是另外一个复杂的话题,本人也学习中...
能想起的好象就这些了,可能不是很完善,希望有人能补充!
你可能平时编程时没有注意。在 SQLCA(Transaction)默认情况下 AutoCommit= false(不自动提交)。在同一事务中,如果不提交事务,
可以SELECT、Retrieve,但其它事务(其它计算机的应用程序连接数据库的事务)就不能。所以导致死锁,而在单机开发环境看不出来。
你需要在所有的 UPDATE、DELETE的SQL语句后面,或者数据窗口的Update函数调用之后执行 COMMIT或 ROLLBACK
补充一点,除了在执行了Update,Delete,Insert需要及时Commit外,在SQL Server中由于使用一个Tempdb的数据库,这个数据库是对所有用户共享
的,当使用了统计类型的SQL函数如:sum,count等,SQL Server会自动使用Tempdb进行暂存统计数据,这样很容易造成Tempdb被锁住,所以在读取了
一个很复杂Store Procedure或创建过临时表后应进行commit,以便释放Tempdb资源,在retrieved事件中加commit是一个解决办法,特别是在读取
报表后更应加,一般报表的Store Procedure都比较复杂,在程序中内嵌了SQL光标来读取数据后也要加commit,我增经试过被锁住,找了很久才知
二、sql server中如何避免死锁
一、死锁的四个必要条件
1、互斥条件(Mutual
exclusion):资源不能被共享,只能由一个进程使用。
2、请求与保持条件(Hold
and
wait):已经得到资源的进程可以再次申请新的资源。
3、非剥夺条件(No
pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。
4、循环等待条件(Circular
wait):系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。
二、
避免死锁
1、按同一顺序访问对象
如果所有并发事务按同一顺序访问对象,则发生死锁的可能性会降低。例如,如果两个并发事务获得
Supplier
表上的锁,然后获得
Part
表上的锁,则在其中一个事务完成之前,另一个事务被阻塞在
Supplier
表上。第一个事务提交或回滚后,第二个事务继续进行。不发生死锁。将存储过程用于所有的数据修改可以标准化访问对象的顺序。
2、避免事务中的用户交互
避免编写包含用户交互的事务,因为运行没有用户交互的批处理的速度要远远快于用户手动响应查询的速度,例如答复应用程序请求参数的提示。例如,如果事务正在等待用户输入,而用户去吃午餐了或者甚至回家过周末了,则用户将此事务挂起使之不能完成。这样将降低系统的吞吐量,因为事务持有的任何锁只有在事务提交或回滚时才会释放。即使不出现死锁的情况,访问同一资源的其它事务也会被阻塞,等待该事务完成。
3、保持事务简短并在一个批处理中
在同一数据库中并发执行多个需要长时间运行的事务时通常发生死锁。事务运行时间越长,其持有排它锁或更新锁的时间也就越长,从而堵塞了其它活动并可能导致死锁。
保持事务在一个批处理中,可以最小化事务的网络通信往返量,减少完成事务可能的延迟并释放锁。
4、使用低隔离级别
确定事务是否能在更低的隔离级别上运行。执行提交读允许事务读取另一个事务已读取(未修改)的数据,而不必等待第一个事务完成。使用较低的隔离级别(例如提交读)而不使用较高的隔离级别(例如可串行读)可以缩短持有共享锁的时间,从而降低了锁定争夺。
5、使用绑定连接
使用绑定连接使同一应用程序所打开的两个或多个连接可以相互合作。次级连接所获得的任何锁可以象由主连接获得的锁那样持有,反之亦然,因此不会相互阻塞
6、SELECT语句加With(NoLock)提示
默认情况下SELECT语句会对查询到的资源加S锁(共享锁),S锁与X锁(排他锁)不兼容;但加上With(NoLock)后,SELECT不对查询到的资源加锁(或者加Sch-S锁,Sch-S锁可以与任何锁兼容);从而可以是这两条SQL可以并发地访问同一资源。当然,此方法适合解决读与写并发死锁的情况,但加With(NoLock)可能会导致脏读。
三、在SQL中存储过程的一般语法是什么
1、创建语法
createproc|procedurepro_name
[{@参数数据类型}[=默认值][output],
{@参数数据类型}[=默认值][output],
....
]
as
SQL_statements
2、创建不带参数存储过程
--创建存储过程
if(exists(select*fromsys.objectswherename='proc_get_student'))
dropprocproc_get_student
go
createprocproc_get_student
as
select*fromstudent;
--调用、执行存储过程
execproc_get_student;
3、修改存储过程
--修改存储过程
alterprocproc_get_student
as
select*fromstudent;
4、带参存储过程
--带参存储过程
if(object_id('proc_find_stu','P')isnotnull)
dropprocproc_find_stu
go
createprocproc_find_stu(@startIdint,@endIdint)
as
select*fromstudentwhereidbetween@startIdand@endId
go
execproc_find_stu2,4;
5、带通配符参数存储过程
--带通配符参数存储过程
if(object_id('proc_findStudentByName','P')isnotnull)
dropprocproc_findStudentByName
go
createprocproc_findStudentByName(@namevarchar(20)='%j%',@nextNamevarchar(20)='%')
as
select*fromstudentwherenamelike@nameandnamelike@nextName;
go
execproc_findStudentByName;execproc_findStudentByName'%o%','t%';
扩展资料:
SQL存储过程优点:
1、重复使用。存储过程可以重复使用,从而可以减少数据库开发人员的工作量。
2、减少网络流量。存储过程位于服务器上,调用的时候只需要传递存储过程的名称以及参数就可以了,因此降低了网络传输的数据量。
3、安全性。参数化的存储过程可以防止SQL注入式攻击,而且可以将Grant、Deny以及Revoke权限应用于存储过程。
参考资料来源:百度百科—存储过程