当前位置:首页 » 编程语言 » sql存储过程死锁
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

sql存储过程死锁

发布时间: 2022-05-10 12:08:34

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程序需要使用批提交,来保证数据的完成性)

http://www.51onnet.com/bbs/forumdisplay.php?f=6

你可能平时编程时没有注意。在 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 Procere或创建过临时表后应进行commit,以便释放Tempdb资源,在retrieved事件中加commit是一个解决办法,特别是在读取

报表后更应加,一般报表的Store Procere都比较复杂,在程序中内嵌了SQL光标来读取数据后也要加commit,我增经试过被锁住,找了很久才知

❷ sql处理数据库锁的存储过程分享

邹建
2004.4
复制代码
代码如下:
/*--调用示例
exec
p_lockinfo1
--*/
alter
proc
p_lockinfo1
@kill_lock_spid
bit=1,
--是否杀掉死锁的进程,1
杀掉,
0
仅显示
@show_spid_if_nolock
bit=1
--如果没有死锁的进程,是否显示正常进程信息,1
显示,0
不显示
as
declare
@count
int,@s
nvarchar(max),@i
int
select
id=identity(int,1,1),标志,
进程ID=spid,线程ID=kpid,块进程ID=blocked,数据库ID=dbid,
数据库名=db_name(dbid),用户ID=uid,用户名=loginame,累计CPU时间=cpu,
登陆时间=login_time,打开事务数=open_tran,
进程状态=status,
工作站名=hostname,应用程序名=program_name,工作站进程ID=hostprocess,
域名=nt_domain,网卡地址=net_address
into
#t
from(
select
标志='死锁的进程',
spid,kpid,a.blocked,dbid,uid,loginame,cpu,login_time,open_tran,
status,hostname,program_name,hostprocess,nt_domain,net_address,
s1=a.spid,s2=0
from
master..sysprocesses
a
join
(
select
blocked
from
master..sysprocesses
group
by
blocked
)b
on
a.spid=b.blocked
where
a.blocked=0
union
all
select
'|_牺牲品_>',
spid,kpid,blocked,dbid,uid,loginame,cpu,login_time,open_tran,
status,hostname,program_name,hostprocess,nt_domain,net_address,
s1=blocked,s2=1
from
master..sysprocesses
a
where
blocked<>0
)a
order
by
s1,s2
select
@count=@@rowcount,@i=1
if
@count=0
and
@show_spid_if_nolock=1
begin
insert
#t
select
标志='正常的进程',
spid,kpid,blocked,dbid,db_name(dbid),uid,loginame,cpu,login_time,
open_tran,status,hostname,program_name,hostprocess,nt_domain,net_address
from
master..sysprocesses
set
@count=@@rowcount
end
if
@count>0
begin
create
table
#t1(id
int
identity(1,1),a
nvarchar(max),b
Int,EventInfo
nvarchar(max))
if
@kill_lock_spid=1
begin
declare
@spid
varchar(max),@标志
varchar(max)
while
@i<=@count
begin
select
@spid=进程ID,@标志=标志
from
#t
where
id=@i
insert
#t1
exec('dbcc
inputbuffer('+@spid+')')
if
@标志='死锁的进程'
exec('kill
'+@spid)
set
@i=@i+1
end
end
else
while
@i<=@count
begin
select
@s='dbcc
inputbuffer('+cast(进程ID
as
varchar(max))+')'
from
#t
where
id=@i
insert
#t1
exec(@s)
set
@i=@i+1
end
select
a.*,进程的SQL语句=b.EventInfo
from
#t
a
join
#t1
b
on
a.id=b.id
end
go

❸ sql 死锁 和 事物回滚 问题

死锁在数据库事务处理期内,是很难判断死锁的。至于在解除死锁后是否回滚,则与你的事务定义的逻辑关系有关,如果你的语句逻辑严谨的话,人工解除死锁后,数据库能够自动回滚。

避免数据库死锁的最好办法是在关键处理语句部分使用事务机制,并且在编写调用程序时(如C#、VB等),进行严密的判断,尽量避免各种可能的语句冲突。而不是通过存储过程来解决。

❹ 如何查看死锁的”SQL语句“或”存储过程“

假如发生了死锁,我们怎么去检测具体发生死锁的是哪条SQL语句或存储过程?此时我们可以使用以下存储过程来检测,就可以查出引起死锁的进程和SQL语句。

Sql代码
usemaster
go
create proceresp_who_lock
as
begin
declare @spid int,@blint,
@intTransactionCountOnEntryint,
@intRowcountint,
@intCountPropertiesint,
@intCounter int

create table #tmp_lock_who(
id intidentity(1,1),
spidsmallint,
blsmallint)

IF @@ERROR<>0 RETURN@@ERROR

insert into#tmp_lock_who(spid,bl) select 0 ,blocked
from (select * fromsysprocesses where blocked>0 ) a
where not exists(select *from
(select * from sysprocesseswhere blocked>0 ) b
wherea.blocked=spid)
union select spid,blockedfrom sysprocesses where blocked>0

IF @@ERROR<>0 RETURN@@ERROR

-- 找到临时表的记录数
select @intCountProperties= Count(*),@intCounter = 1
from#tmp_lock_who

IF @@ERROR<>0 RETURN@@ERROR

if@intCountProperties=0
select '现在没有阻塞和死锁信息' as message

-- 循环开始
while @intCounter <=@intCountProperties
begin
-- 取第一条记录
select @spid = spid,@bl =bl
from #tmp_lock_who where Id= @intCounter
begin
if @spid=0
select '引起数据库死锁的是: '+ CAST(@bl ASVARCHAR(10))
+ '进程号,其执行的SQL语法如下'
else
select '进程号SPID:'+ CAST(@spid AS VARCHAR(10))
+ '被进程号SPID:'+ CAST(@bl ASVARCHAR(10))
+ '阻塞,其当前进程执行的SQL语法如下'DBCC INPUTBUFFER

use master
go
create proceresp_who_lock
as
begin
declare @spid int,@bl int,
@intTransactionCountOnEntryint,
@intRowcount int,
@intCountProperties int,
@intCounter int

create table #tmp_lock_who(
id int identity(1,1),
spid smallint,
bl smallint)

IF @@ERROR<>0 RETURN@@ERROR

insert into#tmp_lock_who(spid,bl) select 0 ,blocked
from (select * fromsysprocesses where blocked>0 ) a
where not exists(select *from
(select * from sysprocesseswhere blocked>0 ) b
where a.blocked=spid)
union select spid,blockedfrom sysprocesses where blocked>0

IF @@ERROR<>0 RETURN@@ERROR

-- 找到临时表的记录数
select @intCountProperties= Count(*),@intCounter = 1
from #tmp_lock_who

IF @@ERROR<>0 RETURN@@ERROR

if @intCountProperties=0
select '现在没有阻塞和死锁信息' as message

-- 循环开始
while @intCounter <=@intCountProperties
begin
-- 取第一条记录
select @spid = spid,@bl =bl
from #tmp_lock_who where Id= @intCounter
begin
if @spid =0
select '引起数据库死锁的是: '+ CAST(@bl AS VARCHAR(10))
+ '进程号,其执行的SQL语法如下'
else
select '进程号SPID:'+ CAST(@spid AS VARCHAR(10))
+ '被进程号SPID:'+ CAST(@bl AS VARCHAR(10))
+ '阻塞,其当前进程执行的SQL语法如下'DBCC INPUTBUFFER
与锁定有关的两个问题--死锁和阻塞

❺ sql数据库的问题。运行存储过程的时候出现死锁 该怎么解决高分悬赏 只求解答。查跟杀死锁的代码是什么

lock
Select V$SESSION.SID, DBA_OBJECTS.OBJECT_NAME, V$SESSION.OSUSER, V$SESSION.PROGRAM
From V$LOCKED_OBJECT
Left Join DBA_OBJECTS on V$LOCKED_OBJECT.OBJECT_ID = DBA_OBJECTS.OBJECT_ID
Left Join V$SESSION ON V$LOCKED_OBJECT.SESSION_ID = V$SESSION.SID
Order By V$SESSION.SID, DBA_OBJECTS.OBJECT_NAME

unlock(kill session)
alter system kill session 'sid,serial#';

❻ 如何查看SQL Server 2008的死锁

在SQL Server 2008数据库中,查看死锁可以用存储过程来实现,本文我们主要就介绍了SQL Server 2008查看死锁的存储过程的代码示例,希望能够对您有所帮助。
代码示例如下:
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_who_lock]') and OBJECTPROPERTY(id, N'IsProcere') = 1) drop procere [dbo].[sp_who_lock] GO use master go create procere sp_who_lock as begin declare @spid int,@bl int, @intTransactionCountOnEntry int, @intRowcount int, @intCountProperties int, @intCounter int create table #tmp_lock_who ( id int identity(1,1), spid smallint, bl smallint) IF @@ERROR<>0 RETURN @@ERROR insert into #tmp_lock_who(spid,bl) select 0 ,blocked from (select * from sysprocesses where blocked>0 ) a where not exists(select * from (select * from sysprocesses where blocked>0 ) b where a.blocked=spid) union select spid,blocked from sysprocesses where blocked>0 IF @@ERROR<>0 RETURN @@ERROR -- 找到临时表的记录数 select @intCountProperties = Count(*),@intCounter = 1 from #tmp_lock_who IF @@ERROR<>0 RETURN @@ERROR if @intCountProperties=0 select '现在没有阻塞和死锁信息' as message -- 循环开始 while @intCounter <= @intCountProperties begin -- 取第一条记录 select @spidspid = spid,@blbl = bl from #tmp_lock_who where Id = @intCounter begin if @spid =0 select '引起数据库死锁的是: '+ CAST(@bl AS VARCHAR(10)) + '进程号,其执行的SQL语法如下' else select '进程号SPID:'+ CAST(@spid AS VARCHAR(10))+ '被' + '进程号SPID:'+ CAST(@bl AS VARCHAR(10)) +'阻塞,其当前进程执行的SQL语法如下' DBCC INPUTBUFFER (@bl ) end -- 循环指针下移 set @intCounter = @intCounter + 1 end drop table #tmp_lock_who return 0 end

以上就是SQL Server 2008查看死锁的存储过程的代码示例的全部内容,本文我们就介绍到这里了,希望本次的介绍能够对您有所收获!

❼ sql提示死锁

我也曾遇到过这个问题,记得当时我写了一个复杂的存储过程,里面处理了很多个数据表的数据,且在存储过程中使用了事务。
该存储过程在查询分析器中执行需要20秒左右的时间。但到程序中去执行,所需要的时间就要长很多了。而且由于采用事务,容易产生死锁。问题与你的一样。
后来我采取了以下措施,问题便得到改状况,至目前为止没有再出现过此问题:
将你的存储过程进行优化,将需要的数据取到存储中,使用临时表或变量保存,而对于插入数据、删除数据、修改数据、等需要事务的地方,则开启事务,在此之前的处理中,不要使用事务。
另外就是尽量减少对大数据量表的操作次数,优化各句话,使其执行时间快,效率优。尽量降低存储过程的运行时间。减少数据表在事务中锁定的时间。

祝你成功

❽ 如何分析SQLServer中的deadlocktrace

首先我们来看一个简单的例子,大结构非常简单:

1,process-list显示了两个进程之间发生了死锁process60fb88和processd11902c8。

2,vistim-list显示了process60fb88被选为了牺牲者。

2,后面的resource-list显示了两个进程争取并导致死锁的资源。

[html] view plain
<deadlock>
<victim-list>
<victimProcess id="process60fb88" />
</victim-list>
<process-list>
<process id="process60fb88" taskpriority="0" logused="0" waitresource="KEY: 9:72057597664231424 (7506ff9b7b0d)" waittime="4376" ownerId="2656658629" transactionname="SELECT" lasttranstarted="2014-04-09T23:01:35.743" XDES="0x80059940" lockMode="S" schelerid="4" kpid="10640" status="suspended" spid="80" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2014-04-09T23:01:35.657" lastbatchcompleted="2014-04-09T23:01:35.657" clientapp=".Net SqlClient Data Provider" hostname="BODCPRODVSQL128" hostpid="10088" loginname="PROD\s-propdata" isolationlevel="read committed (2)" xactid="2656658629" currentdb="9" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="" line="9" stmtstart="336" stmtend="874" sqlhandle="" />
<frame procname="" line="20" stmtstart="1022" stmtend="1206" sqlhandle="" />
<frame procname="" line="9" stmtstart="464" stmtend="642" sqlhandle="" />
<frame procname="" line="4" stmtstart="224" stmtend="420" sqlhandle="" />
</executionStack>
<inputbuf>

DECLARE @logText NVARCHAR(MAX)

EXEC IntegratedService_ProcessLatestCommand @logText OUTPUT

SELECT @logText </inputbuf>
</process>
<process id="processd11902c8" taskpriority="0" logused="232" waitresource="KEY: 9:72057596808265728 (ed2e944beff9)" waittime="4379" ownerId="2656658630" transactionname="UPDATE" lasttranstarted="2014-04-09T23:01:35.743" XDES="0x80048570" lockMode="X" schelerid="8" kpid="6620" status="suspended" spid="53" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2014-04-09T23:01:34.650" lastbatchcompleted="2014-04-09T23:01:34.650" clientapp=".Net SqlClient Data Provider" hostname="BODCPRODVSQL128" hostpid="10088" loginname="PROD\s-propdata" isolationlevel="read committed (2)" xactid="2656658630" currentdb="9" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="" line="22" stmtstart="1230" stmtend="1496" sqlhandle="" />
<frame procname="" line="20" stmtstart="1022" stmtend="1206" sqlhandle="" />
<frame procname="" line="9" stmtstart="464" stmtend="642" sqlhandle="" />
<frame procname="" line="4" stmtstart="224" stmtend="420" sqlhandle="" />
</executionStack>
<inputbuf>

DECLARE @logText NVARCHAR(MAX)

EXEC IntegratedService_ProcessLatestCommand @logText OUTPUT

SELECT @logText </inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057597664231424" dbid="9" objectname="" indexname="" id="lockc99859500" mode="X" associatedObjectId="72057597664231424">
<owner-list>
<owner id="processd11902c8" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process60fb88" mode="S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057596808265728" dbid="9" objectname="" indexname="" id="lock2f4de2d00" mode="S" associatedObjectId="72057596808265728">
<owner-list>
<owner id="process60fb88" mode="S" />
</owner-list>
<waiter-list>
<waiter id="processd11902c8" mode="X" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>

下面是详细分析。
1,victim-list没什么可分析的。

2,process-list中关于各个process的详细信息很重要。

waitresource="KEY: 9:72057597664231424 (7506ff9b7b0d)"

当前process正在等待的资源。通常我们在resource-list中可以看到同样的信息。使用下面的sql查询等待的资源是什么:

下面使用的hobtid是heap or b-tree id的缩写。详细见sys.partotions的解释。

[sql] view plain
SELECT o.name, i.name
FROM sys.partitions p
JOIN sys.objects o ON p.object_id = o.object_id
JOIN sys.indexes i ON p.object_id = i.object_id
AND p.index_id = i.index_id
WHERE p.hobt_id = 72057597664231

name name
--------------------------------------------------------------------
MatchService PK_Matcher_ID
从结果我们就可以知道,等待的资源是一个表MatchService的主键PK_Matcher_ID。考察另外一个process的waitresource我们可以得知等待的资源是同一个表的另外一个索引。至此我们找到了直接导致死锁的资源是什么。

同时可以看到两个process一个是x lock,一个是s lock。因此可以判定发生在该表上的一个修改语句和一个查询语句之间发生了死锁。

另外,上例中可以清晰的看到是keylock导致的死锁,因此查询partitions可以找到对应的object (sys.partitions contains a row for each partition of all
the tables and most types of indexes in the database.)。但有时是其他类型的资源发生了死锁,例如pagelock, waitresource="PAGE: 9:1:28440841" 。 9是dbid; 1是fileid; 28440841是pageid。对于这种情况,使用下面的语句查询对应的资源:

[sql] view plain
DBCC TRACEON(3604)
GO
DBCC PAGE (9, 1, 28440841)
GO
DBCC TRACEOFF(3604)
GO

从返回的Metadata: objectId找到对应的objectid。

3,再看process中的inputbuf。这个tag表明了process正在运行的语句,因此对于定位死锁非常重要。但这里有一个问题,比如
上例中,inputbuf是一个存储过程,其中又嵌套了很多其他的存储过程,但inputbuf是用户直接发出的sql,而我们需要在其中找出直接导致死
锁的语句并优化,从而解决或减少死锁。自此我们已经有的信息是:导致死锁的语句由inputbuf中的语句调用,同时导致死锁的语句必定是对表
MatchService的修改语句。如果存储过程很简单,到此DBA已经能够找到直接导致死锁的sql了,分析过程到此结束。而如果存储过程很复杂,则
需要进一步分析。

4,现在再进一步考察tag, executionStack。executionStack表明了死锁发生时,由inputbuf调用的一系列
sql。上例中有4条sql。同时仔细观察上例可以发生,两个process的executionStack是完全相同的,因此考察一个就可以了。另外,
如果procname不为空则直接得到了sql,但上例中该tag为空。

自此我们希望把executionStack中的所有sql显示出来。使用下面的sql找出sqlhandle对应的在内存中的sql。需要注意的
是,如果deadlock已经过去了一段时间,sqlhandle可能已经被从内存中清除掉了,这时就不可查了。还有sqlhandle是
varbinaryd,所以查询时不可加引号。

另外还有一个有趣的地方:和其他程序语言报错时一样,stack最上的一条是最直接的错误,后面的错误都是该错误的上一层错误(这么解释可能有点
乱,写过代码的同学能理解哈)。因此在上面说的存储过程调用存储过程的情况中,executionStack中第一条是直接导致死锁的sql,第二条是调
用该sql的sql,以此类推,最后一条理论上就是inputbuf中的sql。

[sql] view plain
SELECT sql_handle AS Handle,
SUBSTRING(st.text, (qs.statement_start_offset/2)+1,
((CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(st.text)
ELSE qs.statement_end_offset
END - qs.statement_start_offset)/2) + 1) AS Text
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
where sql_handle =
order by sql_handle

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


TOP 1 @matcherQueueID = lhs.MatcherService_MatcherQueue_ID,
@rootOperationUID = Root_Operation_UID FROM
MatcherService_MatcherQueue lhs WHERE lhs.Processing_State
= 'MATCHING' OR lhs.Processing_State = 'MATCHED' ORDER BY
Last_Execution_Date ASC

SELECT Top 1 @ticketID = OperationLog_ID FROM GEDemo.dbo.OperationLog
WHERE @rootOperationUID = Root_Operation_UID AND Status = 0
ORDER BY OperationLog_ID ASC

UPDATE MatcherService_MatcherQueue SET Last_Execution_Date =
GETDATE() WHERE MatcherService_MatcherQueue_ID = @matcherQueueID

注意看起来一个sql_handle有三条语句,原因是这三条sql是属于同一个存储过程的。

如果一个sql_handle包含的语句很多,比如是一个很长的存储过程,那么我们还可以使用一个有力的信息:executionStack中的
line
tag.这条语句表明了到底是哪一个sql直接导致了死锁。如果一条statement中又包含了很多表,那么还需要和死锁的资源结合起来判断是哪个表或
索引的数据发生了死锁。

❾ SQL SERVER一个数据库中使用大量的存储过程,会影响性能吗

一、在SQL Server中存储过程不会影响性能。
1、只会大大的减轻服务器的压力,而不会增加,只有不合理的存储过程才会造成服务器性能下降的恶果。一个大型的数据库,一般存储过程也不会超过几千个,对当前的数据库及它依附的硬件来说,这点儿负载是大象身上的老鼠,负载基本可以怱略不计。
2、但是,存储过程是批量的SQL语句的合成,如果设计上混乱,引发死循环、死锁、大范围查询、临时表没有及时清理释放等问题的情况下,是会严重影响服务器性能的,但这根子不在存储过程上,而在于存储过程的设计上。错误的SQL代码指挥服务器,无论它的形式是存储过程,还是客户端及时发向数据库的请求,都会使服务器出现问题。

二、相关扩展
1、在当前,针对数据库的编程设计,没有存储过程是不可想象的,这就象某个公司的大型货品仓库中没有仓库保管员一样,所有的货品进出都得进货员或销售员去临时取放,会严重降低工作效率。
2、存储过程在数据库中无论是否编译好,其效率都要比客户端临时向数据库发送指令调数据来得要高,因为至少减少了发向服务器的指令的量。况且很多的中间值、临时值如果不通过存储过程来实现的话,就只能先全取到客户端,这样会大大增加网络负担与服务器的负钽。
3、正如微软所说,存储过程来实现,可以使得很多中间量不必传入到客户上,客户端只能得到需要的结果,所以同时可以提高安全。