❶ 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、正如微軟所說,存儲過程來實現,可以使得很多中間量不必傳入到客戶上,客戶端只能得到需要的結果,所以同時可以提高安全。