當前位置:首頁 » 編程語言 » sql避免死鎖
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

sql避免死鎖

發布時間: 2023-05-11 15:18:20

sql:下面哪個鎖防止你的資料庫鎖死

答案是B,更新鎖!解答如下:
共享鎖
共享 (S) 鎖允許並發事務讀取 (SELECT) 一個資源。資源上存在共享 (S) 鎖時,任何其它事務都不能修改數據。一旦已經讀取數據,便立即釋放資源上的共享 (S) 鎖,除非將事務隔離級別設置為可重復讀或更高級別,或者在事務生存周期內用鎖定提示保留共享 (S) 鎖。

更新鎖
更新 (U) 鎖可以防止通常形式的死鎖。一般更新模式由一個事務組成,此事務讀取記錄,獲取資源(頁或行)的共享 (S) 鎖,然後修改行,此操作要求鎖轉換為排它 (X) 鎖。如果兩個事務獲得了資源上的共享模式鎖,然後試圖同時更新數據,則一個事務嘗試將鎖轉換為排它 (X) 鎖。共享模式到排它鎖的轉換必須等待一段時間,因為一個事務的排它鎖與其它事務的共享模式鎖不兼容;發生鎖等待。第二個事務試圖獲取排它 (X) 鎖以進行更新。由於兩個事務都要轉換為排它 (X) 鎖,並且每個事務都等待另一個事務釋放共享模式鎖,因此發生死鎖。

若要避免這種潛在的死鎖問題,請使用更新 (U) 鎖。一次只有一個事務可以獲得資源的更新 (U) 鎖。如果事務修改資源,則更新 (U) 鎖轉換為排它 (X) 鎖。否則,鎖轉換為共享鎖。

排它鎖
排它 (X) 鎖可以防止並發事務對資源進行訪問。其它事務不能讀取或修改排它 (X) 鎖鎖定的數據。

意向鎖
意向鎖表示 SQL Server 需要在層次結構中的某些底層資源上獲取共享 (S) 鎖或排它 (X) 鎖。例如,放置在表級的共享意向鎖表示事務打算在表中的頁或行上放置共享 (S) 鎖。在表級設置意向鎖可防止另一個事務隨後在包含那一頁的表上獲取排它 (X) 鎖。意向鎖可以提高性能,因為 SQL Server 僅在表級檢查意向鎖來確定事務是否可以安全地獲取該表上的鎖。而無須檢查表中的每行或每頁上的鎖以確定事務是否可以鎖定整個表。

意向鎖包括意向共享 (IS)、意向排它 (IX) 以及與意向排它共享 (SIX)。

⑵ 資料庫中死鎖是什麼產生的

資料庫操作的死鎖是不可避免的,本文並不打算討論死鎖如何產生,重點在於解決死鎖,通過SQL Server 2005, 現在似乎有了一種新的解決辦法。

將下面的SQL語句放在兩個不同的連接裡面,並且在5秒內同時執行,將會發生死鎖。

use Northwind
begin tran
insert into Orders(CustomerId) values(@#ALFKI@#)
waitfor delay @#00:00:05@#
select * from Orders where CustomerId = @#ALFKI@#
commit
print @#end tran@#

SQL Server對付死鎖的辦法是犧牲掉其中的一個,拋出異常,並且回滾事務。在SQL Server 2000,語句一旦發生異常,T-SQL將不會繼續運行,上面被犧牲的連接中, print @#end tran@#語句將不會被運行,所以我們很難在SQL Server 2000的T-SQL中對死鎖進行進一步的處理。

現在不同了,SQL Server 2005可以在T-SQL中對異常進行捕獲,這樣就給我們提供了一條處理死鎖的途徑:

下面利用的try ... catch來解決死鎖。

SET XACT_ABORT ON
declare @r int
set @r = 1
while @r <= 3
begin
begin tran

begin try
insert into Orders(CustomerId) values(@#ALFKI@#)
waitfor delay @#00:00:05@#
select * from Orders where CustomerId = @#ALFKI@#

commit
break
end try

begin catch
rollback
waitfor delay @#00:00:03@#
set @r = @r + 1
continue
end catch
end

解決方法當然就是重試,但捕獲錯誤是前提。rollback後面的waitfor不可少,發生沖突後需要等待一段時間,@retry數目可以調整以應付不同的要求。

但是現在又面臨一個新的問題: 錯誤被掩蓋了,一但問題發生並且超過3次,異常卻不會被拋出。SQL Server 2005 有一個RaiseError語句,可以拋出異常,但卻不能直接拋出原來的異常,所以需要重新定義發生的錯誤,現在,解決方案變成了這樣:

declare @r int
set @r = 1
while @r <= 3
begin
begin tran

begin try
insert into Orders(CustomerId) values(@#ALFKI@#)
waitfor delay @#00:00:05@#
select * from Orders where CustomerId = @#ALFKI@#

commit
break
end try

begin catch
rollback
waitfor delay @#00:00:03@#
set @r = @r + 1
continue
end catch
end
if ERROR_NUMBER() <> 0
begin
declare @ErrorMessage nvarchar(4000);
declare @ErrorSeverity int;
declare @ErrorState int;
select
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
raiserror (@ErrorMessage,
@ErrorSeverity,
@ErrorState
);
end

⑶ SQL SERVER怎樣才能有效避免死鎖

你可以晌滑態採取以下方法將死鎖減至最少:
•按同一順序訪問對象。
•避免事務中的用戶交互讓伏。
•保持事務簡短並處於一個批處理中。
•使用較低的隔離級別。
•使用基於行版本控制的隔離級別。
a.將 READ_COMMITTED_SNAPSHOT 資料庫選項設置為 ON,使得已提交讀事務使用行版本控制。
b.使用快照隔離宴源。
•使用綁定連接。

⑷ SQLServer死鎖的解除方法

SQL Server死鎖使我們經常遇到的問題 下面就為您介紹如何查詢SQL Server死鎖 希望對您學習SQL Server死鎖方面能有所幫助

SQL Server死鎖的查詢方法

exec master dbo p_lockinfo 顯示死鎖的進程 不顯示正常的進程

exec master dbo p_lockinfo 殺死死鎖的進程 不顯示正常的進程

SQL Server死鎖的解除方法

Create proc p_lockinfo

@kill_lock_spid bit= 是否殺掉死鎖的進程 殺掉 僅顯示

@show_spid_if_nolock bit= 如果沒有死鎖的進程 是否顯示正常進程信息 顯示 不顯示

as

declare @count int @s nvarchar( ) @i int

select id=identity(int ) 標志

進程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

s =a spid s =

from mastersysprocesses a join (

select blocked from mastersysprocesses group by blocked

)b on a spid=b blocked where a blocked=

union all

select |_犧牲品_>

spid kpid blocked dbid uid loginame cpu login_time open_tran

status hostname program_name hostprocess nt_domain net_address

s =blocked s =

from mastersysprocesses a where blocked<>

)a order by s s

select @count=@@rowcount @i=

if @count= and @show_spid_if_nolock=

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 mastersysprocesses

set @count=@@rowcount

end

if @count>

begin

create table #t (id int identity( ) a nvarchar( ) b Int EventInfo nvarchar( ))

if @kill_lock_spid=

begin

declare @spid varchar( ) @標志 varchar( )

while @i<=@count

begin

select @spid=進程ID @標志=標志 from #t whereid=@i

insert #t exec( dbcc inputbuffer( +@spid+ ) )

if @標志= 死鎖的進程 exec( kill +@spid)

set @i=@i+

end

end

else

while @i<=@count

begin

select @s= dbcc inputbuffer( +cast(進程ID as varchar)+ ) from #t whereid=@i

insert #t exec(@s)

set @i=@i+

end

select a * 進程的SQL語句=b EventInfo

from #t a join #t b on a id=b id

lishixin/Article/program/SQLServer/201311/22183

⑸ 如何減少SQL Server死鎖發生

死鎖是指在某組資源中 兩個或兩個以上的線程在執行過程中 在爭奪某一資源時而造成互相等待的現象 若無外力的作用下 它們都將無法推進下去 死時就可能會產生死鎖 這些永遠在互相等待的進程稱為死鎖線程 簡單的說 進程A等待進程B釋放他的資源 B又等待A釋放他的資源 這樣互相等待就形成死鎖

如在資料庫中 如果需要對一條數據進行修改 首先資料庫管理系統會在上面加鎖 以保證在同一時間只跡扒瞎有一個事務能進行修改操作 如事務 的線程 T 具有表A上的排它鎖 事務 的線程T 具有表B上的排它鎖 並且之後需要表A上的鎖 事務 無法獲得這一鎖 因為事務 已擁有它 事務 被阻塞 等待事務 然後 事務 需要表B的鎖 但無法獲得鎖 因為事務 將它鎖定了 事務在提交或回滾之前不能釋放持有的鎖 因為事務需要對方控制的鎖才能繼續操作 所以它們不能提交或回滾 這樣資料庫就會發生死鎖了

如在編此笑寫存儲過程的時候 由於有些存儲過程事務性姿空的操作比較頻繁 如果先鎖住表A 再鎖住表B 那麼在所有的存儲過程中都要按照這個順序來鎖定它們 如果無意中某個存儲過程中先鎖定表B 再鎖定表A 這可能就會導致一個死鎖 而且死鎖一般是不太容易被發現的

如果伺服器上經常出現這種死鎖情況 就會降低伺服器的性能 所以應用程序在使用的時候 我們就需要對其進行跟蹤 使用sp_who和sp_who 來確定可能是哪些用戶阻塞了其他用戶 我們還可以用下面的存儲過程來跟蹤具體的死鎖執行的影響

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( ) spid *** allint bl *** allint)IF @@ERROR<> RETURN

@@ERRORinsert into

#tmp_lock_who(spid bl) select

blockedfrom (select * from sysprocesses where

blocked> )

a where not exists(select * from (select * from sysprocesses where blocked> )

b where a blocked=spid)union select spid blocked from sysprocesses where

blocked> IF

@@ERROR<> RETURN @@ERROR 找到臨時表的記錄數select

@intCountProperties = Count(*) @intCounter = from #tmp_lock_whoIF

@@ERROR<> RETURN @@ERROR if @intCountProperties= select

現在沒有阻塞和死鎖信息

as message 循環開始while @intCounter <= @intCountPropertie *** egin 取第一條記錄select

@spid = spid @bl = blfrom #tmp_lock_who where id = @intCounter beginif @spid = select

引起資料庫死鎖的是: + CAST(@bl AS VARCHAR( )) + 進程號

其執行的SQL語法如下 elseselect

進程號SPID + CAST(@spid AS VARCHAR( ))+ 被 +

進程號SPID + CAST(@bl AS VARCHAR( )) + 阻塞

當前進程執行的SQL語法如下 DBCC INPUTBUFFER (@bl )end

循環指針下移set @intCounter = @intCounter + enddrop table #tmp_lock_who

return

我們只需要通過在查詢分析器裡面執行sp_who_lock 就可以具體捕捉到執行的堵塞進程 這時我們就可以對對應的SQL語句或者存儲過程進行性能上面的改進及設計

所以我們在資料庫設計的時候 雖然不能完全避免死鎖 但可以使死鎖的數量盡量減少 增加事務的吞吐量並減少系統開銷 因為只有很少的事務 所以就得遵循下面的原則

按同一順序訪問對象

如果所有並發事務按同一順序訪問對象 則發生死鎖的可能性會降低 在寫SQL語句或存儲過程的時候 就需要按照順序在兩個並發事務中先獲得表A上的鎖 然後獲得表B上的鎖 當第一個事務完成之前 另一個事務被阻塞在表A上 第一個事務提交或回滾後 第二個事務繼續進行 而不能在語句裡面寫先獲得表B上的鎖 然後再獲得表A的鎖

避免事務中的用戶交互

避免編寫包含用戶交互的事務 因為運行沒有用戶交互的批處理的速度要遠遠快於用戶手動響應查詢的速度 例如答復應用程序請求參數的提示 例如 如果事務正在等待用戶輸入 而用戶就去做別的事了 則用戶將此事務掛起使之不能完成 這樣將降低系統的吞吐量 因為事務持有的任何鎖只有在事務提交或回滾時才會釋放 即使不出現死鎖的情況 訪問同一資源的其它事務也會被阻塞 等待該事務完成

保持事務簡短並在一個批處理中

在同一資料庫中並發執行多個需要長時間運行的事務時通常發生死鎖 事務運行時間越長 其持有排它鎖或更新鎖的時間也就越長 從而堵塞了其它活動並可能導致死鎖 保持事務在一個批處理中 可以最小化事務的網路通信往返量 減少完成事務可能的延遲並釋放鎖

使用低隔離級別

確定事務是否能在更低的隔離級別上運行 執行提交讀允許事務讀取另一個事務已讀取(未修改)的數據 而不必等待第一個事務完成 使用較低的隔離級別(例如提交讀)而不使用較高的隔離級別(例如可串列讀)可以縮短持有共享鎖的時間 從而降低了鎖定爭奪

使用綁定連接

使用綁定連接使同一應用程序所打開的兩個或多個連接可以相互合作 次級連接所獲得的任何鎖可以象由主連接獲得的鎖那樣持有 反之亦然 因此不會相互阻塞

下面有一些對死鎖發生的一些建議

)對於頻繁使用的表使用集簇化的索引;

)設法避免一次性影響大量記錄的T SQL語句 特別是INSERT和UPDATE語句;

)設法讓UPDATE和DELETE語句使用索引;

)使用嵌套事務時 避免提交和回退沖突;

lishixin/Article/program/SQLServer/201311/22281

⑹ 「sql」加鎖機制是什麼

您好!鎖是資料庫中的一個非常重要的概念,它主要用於多用戶環境下保證資料庫完整性和一致性。x0dx0a 我們知道,多個用戶能夠同時操縱同一個資料庫中的數據,會發生數據不一致現象。即如果沒有鎖定且多個用戶同時訪問一個資料庫,則當他們的事務同時使用相同的數據時可能會發生問題。這些問題包括:丟失更新、臟讀、不可重復讀和幻覺讀。資料庫加鎖就是為了解決以上的問題。x0dx0a 當然,加鎖固然好,但是一定要避免死鎖的出現。x0dx0a 在資料庫系統中,死鎖是指多個用戶(進程)分別鎖定了一個資源,並又試圖請求鎖定對方已經鎖定的資源,這就產生了一個鎖定請求環,導致多個用戶(進程)都處於等待對方釋放所鎖定資源的狀態。這種死鎖是最典型的死鎖形式, 例如在同一時間內有兩個事務A和B,事務A有兩個操作:鎖定表part和請求訪問表supplier;事務B也有兩個操作:鎖定表supplier和請求訪問表part。結果,事務A和事務B之間發生了死鎖。死鎖的第二種情況是,當在一個資料庫中時,有若干個長時間運行的事務執行並行的褲拆操作,當查詢分析器處理一種非常復雜的查詢例如連接查詢時,那麼由於不能控制處理的順序,有可能發生死鎖現象。x0dx0a 在應用程序中就可以採用下面的一些方法來盡量避胡棚棗免死鎖了: (1)合理安排表訪問順序。 (2)在事務中盡量避免用戶干預,盡量使一個事務處理的任務少些, 保持事務簡短並在一個批處理中。 (3)數據訪問時域離散法, 數據訪問時域離散法是指在客戶機/伺服器結構中,採取各種控制手段控制對資料庫或資料庫中的和手對象訪問時間段。主要通過以下方式實現: 合理安排後台事務的執行時間,採用工作流對後台事務進行統一管理。工作流在管理任務時,一方面限制同一類任務的線程數(往往限制為1個),防止資源過多佔用; 另一方面合理安排不同任務執行時序、時間,盡量避免多個後台任務同時執行,另外, 避免在前台交易高峰時間運行後台任務。 (4)數據存儲空間離散法。數據存儲空間離散法是指採取各種手段,將邏輯上在一個表中的數據分散到若干離散的空間上去,以便改善對表的訪問性能。主要通過以下方法實現: 第一,將大表按行或列分解為若干小表; 第二,按不同的用戶群分解。 (5)使用盡可能低的隔離性級別。隔離性級別是指為保證資料庫數據的完整性和一致性而使多用戶事務隔離的程度,SQL92定義了4種隔離性級別:未提交讀、提交讀、可重復讀和可串列。如果選擇過高的隔離性級別,如可串列,雖然系統可以因實現更好隔離性而更大程度上保證數據的完整性和一致性,但各事務間沖突而死鎖的機會大大增加,大大影響了系統性能。 (6)使用綁定連接, 綁定連接允許兩個或多個事務連接共享事務和鎖,而且任何一個事務連接要申請鎖如同另外一個事務要申請鎖一樣,因此可以允許這些事務共享數據而不會有加鎖的沖突。 x0dx0a 總之,了解SQL Server的鎖機制,掌握資料庫鎖定方法, 對一個合格的DBA來說是很重要的。

⑺ GBase 8s中如何避免死鎖問答

鎖的問題(鎖等待、死鎖)大部分由於沒有正確理解鎖的管理、使用方式導致。要解決鎖的問題,我們可以從如下幾個方面進行嘗試。
1.資料庫鎖資源的設置
ONCONFIG 參數 LOCKS 設置即為資料庫配置數量合適的鎖。通過搜索 online 日誌是否有動態增加鎖的情況:grep 'dynamically allocated' online.log為表設置合理的鎖模式、行級鎖或者頁級鎖。
2.應用程序鎖使用模式設置
通過 onstat -g sql 查看 SESSION 使用的鎖等待模式和隔離級別,要為不同的應用設置合理的隔離級別和鎖等待模式。如在應用程序加入如下語句:
set isolation to dirty read;
set lock mode to wait 5;
3.應用程序避免使用不必要的鎖
許多應用程序的 SQL 語句由於沒有正確地使用索引 INDEX,導致對整個表進行了鎖定,導致並發遇到鎖的問題。需要通過 SQL 優化和創建合理的索引,避免順序掃描帶來的鎖沖突問題。
由於順序掃描導致的鎖等待問題:創建表 test_lock,採用行級鎖,並在 c1 欄位上創建索引,插入 3 行測試數據。
create table test_lock (c1 int,c2 int,c3 char(10)) lock mode row;
create index idx_test_lock on test_lock(c1);
insert into test_lock values(1,1,'abc');
insert into test_lock values(2,2,'abc');
insert into test_lock values(3,3,'abc');
Session 1 通過索引掃描來修改第 2 行記錄:
Begin work;
update test_lock set c3='new' where c1=2;
此時,Session 1 將在第二行記錄上加 X 鎖。
Session 2 通過 c2 欄位以順序掃描的方式來修改第 3 行記錄。
Begin work;
update test_lock set c3='new' where c2=3;
由於 Session 2 採用順序掃描方式,在掃描過程中發現第 2 行記錄加上了 X 鎖,故提示鎖沖突錯誤:
244: Could not do a physical-order read to fetch next row.
107: ISAM error: record is locked.
如果在 c2 欄位上加上索引,或者通過 c1=3 修改第三行記錄,那麼就不會出現鎖的問題。
4.應用程序優化避免過長佔用鎖
鎖是一個公共資源,需要盡快釋放鎖資源,減少等待,如果每個事務都可以在微秒級別完成,那麼鎖就不會是我們關注的問題,減少鎖佔用的時間也是解決鎖問題的關鍵。我們可以通過避免大事務,把大事務拆分多次提交,這樣鎖就能盡快釋放。另外,優化應用的處理性能,如合理使用索引等,都可以加快事務的處理速度,可無形中解決鎖沖突的可能性。
5.設置合理的隔離級別
不同的隔離級別對鎖的使用不一樣,設置合理的隔離級別,可以提高應用程序的並發性,提高系統的處理能力,減少鎖的沖突情況,避免讀操作帶來的鎖問題。

⑻ 如何處理SQL Server死鎖問題

死鎖,簡而言之,兩個或者多個trans,同時請求對方正在請求的某個對象,導致雙方互相等待。簡單的例子如下:x0dx0a trans1 trans2x0dx0a ------------------------------------------------------------------------x0dx0a 1.IDBConnection.BeginTransaction 1.IDBConnection.BeginTransactionx0dx0a 2.update table A 2.update table Bx0dx0a 3.update table B 3.update table Ax0dx0a 4.IDBConnection.Commit 4.IDBConnection.Commit x0dx0a 那麼,很容易看到,如果trans1和trans2,分別到達了step3,那麼trans1會請求對於B的X鎖,trans2會請求對於A的X鎖,而二者的鎖在step2上已經被對方分別持有了。由於得不到鎖,後面的Commit無法執行,這樣雙方開始死鎖。x0dx0a 好,我們看一個簡單的例子,來解釋一下,應該如何解決死鎖問題。x0dx0a -- Batch #1x0dx0a CREATE DATABASE deadlocktestx0dx0a GOx0dx0a USE deadlocktestx0dx0a SET NOCOUNT ONx0dx0a DBCC TRACEON (1222, -1)x0dx0a -- 在SQL2005中,增加了一個新的dbcc參數,就是1222,原來在2000下,我們知道,可以執行dbcc x0dx0a --traceon(1204,3605,-1)看到所有的死鎖信息。SqlServer 2005中,對於1204進行了增強,這就是1222。x0dx0a GO x0dx0a x0dx0a IF OBJECT_ID ('t1') IS NOT NULL DROP TABLE t1x0dx0a IF OBJECT_ID ('p1') IS NOT NULL DROP PROC p1x0dx0a IF OBJECT_ID ('p2') IS NOT NULL DROP PROC p2x0dx0a GOx0dx0a CREATE TABLE t1 (c1 int, c2 int, c3 int, c4 char(5000)) x0dx0a GOx0dx0a DECLARE @x intx0dx0a SET @x = 1x0dx0a WHILE (@x <= 1000) BEGINx0dx0a INSERT INTO t1 VALUES (@x*2, @x*2, @x*2, @x*2)x0dx0a SET @x = @x + 1x0dx0a ENDx0dx0a GOx0dx0a CREATE CLUSTERED INDEX cidx ON t1 (c1)x0dx0a CREATE NONCLUSTERED INDEX idx1 ON t1 (c2)x0dx0a GOx0dx0a CREATE PROC p1 @p1 int AS SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+1x0dx0a GOx0dx0a CREATE PROC p2 @p1 int ASx0dx0a UPDATE t1 SET c2 = c2+1 WHERE c1 = @p1x0dx0a UPDATE t1 SET c2 = c2-1 WHERE c1 = @p1x0dx0a GOx0dx0a 上述sql創建一個deadlock的示範資料庫,插入了1000條數據,並在表t1上建立了c1列的聚集索引,和c2列的非聚集索引。另外創建了兩個sp,分別是從t1中select數據和update數據。 x0dx0a 好,打開一個新的查詢窗口,我們開始執行下面的query:x0dx0a -- Batch #2x0dx0a USE deadlocktestx0dx0a SET NOCOUNT ONx0dx0a WHILE (1=1) EXEC p2 4x0dx0a GOx0dx0a 開始執行後,然後我們打開第三個查詢窗口,執行下面的query:x0dx0a -- Batch #3x0dx0a USE deadlocktestx0dx0a SET NOCOUNT ONx0dx0a CREATE TABLE #t1 (c2 int, c3 int)x0dx0a GOx0dx0a WHILE (1=1) BEGINx0dx0a INSERT INTO #t1 EXEC p1 4x0dx0a TRUNCATE TABLE #t1x0dx0a ENDx0dx0a GOx0dx0a 開始執行,哈哈,很快,我們看到了這樣的錯誤信息:x0dx0a Msg 1205, Level 13, State 51, Procere p1, Line 4x0dx0a Transaction (Process ID 54) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.x0dx0a spid54發現了死鎖。 x0dx0a 那麼,我們該如何解決它?x0dx0a 在SqlServer 2005中,我們可以這么做:x0dx0a 1.在trans3的窗口中,選擇EXEC p1 4,然後right click,看到了菜單了嗎?選擇Analyse Query in Database Engine Tuning Advisor。x0dx0a 2.注意右面的窗口中,wordload有三個選擇:負載文件、表、查詢語句,因為我們選擇了查詢語句的方式,所以就不需要修改這個radio option了。x0dx0a 3.點左上角的Start Analysis按鈕x0dx0a 4.抽根煙,回來後看結果吧!出現了一個分析結果窗口,其中,在Index Recommendations中,我們發現了一條信息:大意是,在表t1上增加一個非聚集索引索引:t2+t1。x0dx0a 5.在當前窗口的上方菜單上,選擇Action菜單,選擇Apply Recommendations,系統會自動創建這個索引。x0dx0a 重新運行batch #3,呵呵,死鎖沒有了。x0dx0a 這種方式,我們可以解決大部分的Sql Server死鎖問題。那麼,發生這個死鎖的根本原因是什麼呢?為什麼增加一個non clustered index,問題就解決了呢? 這次,我們分析一下,為什麼會死鎖呢?再回顧一下兩個sp的寫法:x0dx0a CREATE PROC p1 @p1 int AS x0dx0a SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+1 x0dx0a GOx0dx0a CREATE PROC p2 @p1 int ASx0dx0a UPDATE t1 SET c2 = c2+1 WHERE c1 = @p1x0dx0a UPDATE t1 SET c2 = c2-1 WHERE c1 = @p1x0dx0a GOx0dx0a 很奇怪吧!p1沒有insert,沒有delete,沒有update,只是一個select,p2才是update。這個和我們前面說過的,trans1裡面updata A,update B;trans2裡面upate B,update A,根本不貼邊啊!x0dx0a 那麼,什麼導致了死鎖?x0dx0a 需要從事件日誌中,看sql的死鎖信息:x0dx0a Spid X is running this query (line 2 of proc [p1], inputbuffer 「? EXEC p1 4 ?」): x0dx0a SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+1x0dx0a Spid Y is running this query (line 2 of proc [p2], inputbuffer 「EXEC p2 4」): x0dx0a UPDATE t1 SET c2 = c2+1 WHERE c1 = @p1x0dx0a x0dx0a The SELECT is waiting for a Shared KEY lock on index t1.cidx. The UPDATE holds a conflicting X lock. x0dx0a The UPDATE is waiting for an eXclusive KEY lock on index t1.idx1. The SELECT holds a conflicting S lock.x0dx0a 首先,我們看看p1的執行計劃。怎麼看呢?可以執行set statistics profile on,這句就可以了。下面是p1的執行計劃x0dx0a SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+1x0dx0a |--Nested Loops(Inner Join, OUTER REFERENCES:([Uniq1002], [t1].[c1]))x0dx0a |--Index Seek(OBJECT:([t1].[idx1]), SEEK:([t1].[c2] >= [@p1] AND [t1].[c2] <= [@p1]+(1)) ORDERED FORWARD)x0dx0a |--Clustered Index Seek(OBJECT:([t1].[cidx]), SEEK:([t1].[c1]=[t1].[c1] AND [Uniq1002]=[Uniq1002]) LOOKUP ORDERED FORWARD)x0dx0a 我們看到了一個nested loops,第一行,利用索引t1.c2來進行seek,seek出來的那個rowid,在第二行中,用來通過聚集索引來查找整行的數據。這是什麼?就是bookmark lookup啊!為什麼?因為我們需要的c2、c3不能完全的被索引t1.c1帶出來,所以需要書簽查找。 x0dx0a 好,我們接著看p2的執行計劃。x0dx0a UPDATE t1 SET c2 = c2+1 WHERE c1 = @p1x0dx0a |--Clustered Index Update(OBJECT:([t1].[cidx]), OBJECT:([t1].[idx1]), SET:([t1].[c2] = [Expr1004]))x0dx0a |--Compute Scalar(DEFINE:([Expr1013]=[Expr1013]))x0dx0a |--Compute Scalar(DEFINE:([Expr1004]=[t1].[c2]+(1), [Expr1013]=CASE WHEN CASE WHEN ...x0dx0a |--Top(ROWCOUNT est 0)x0dx0a |--Clustered Index Seek(OBJECT:([t1].[cidx]), SEEK:([t1].[c1]=[@p1]) ORDERED FORWARD) x0dx0a 通過聚集索引的seek找到了一行,然後開始更新。這里注意的是,update的時候,它會申請一個針對clustered index的X鎖的。x0dx0a 實際上到這里,我們就明白了為什麼update會對select產生死鎖。update的時候,會申請一個針對clustered index的X鎖,這樣就阻塞住了(注意,不是死鎖!)select裡面最後的那個clustered index seek。死鎖的另一半在哪裡呢?注意我們的select語句,c2存在於索引idx1中,c1是一個聚集索引cidx。問題就在這里!我們在p2中更新了c2這個值,所以sqlserver會自動更新包含c2列的非聚集索引:idx1。而idx1在哪裡?就在我們剛才的select語句中。而對這個索引列的更改,意味著索引集合的某個行或者某些行,需要重新排列,而重新排列,需要一個X鎖。x0dx0a SO???,問題就這樣被發現了。x0dx0a 總結一下,就是說,某個query使用非聚集索引來select數據,那麼它會在非聚集索引上持有一個S鎖。當有一些select的列不在該索引上,它需要根據rowid找到對應的聚集索引的那行,然後找到其他數據。而此時,第二個的查詢中,update正在聚集索引上忙乎:定位、加鎖、修改等。但因為正在修改的某個列,是另外一個非聚集索引的某個列,所以此時,它需要同時更改那個非聚集索引的信息,這就需要在那個非聚集索引上,加第二個X鎖。select開始等待update的X鎖,update開始等待select的S鎖,死鎖,就這樣發生鳥。 x0dx0a 那麼,為什麼我們增加了一個非聚集索引,死鎖就消失鳥?我們看一下,按照上文中自動增加的索引之後的執行計劃:x0dx0a SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+1x0dx0a |--Index Seek(OBJECT:([deadlocktest].[dbo].[t1].[_dta_index_t1_7_2073058421__K2_K1_3]), SEEK:([deadlocktest].[dbo].[t1].[c2] >= [@p1] AND [deadlocktest].[dbo].[t1].[c2] <= [@p1]+(1)) ORDERED FORWARD)x0dx0a 哦,對於clustered index的需求沒有了,因為增加的覆蓋索引已經足夠把所有的信息都select出來。就這么簡單。x0dx0a 實際上,在sqlserver 2005中,如果用profiler來抓eventid:1222,那麼會出現一個死鎖的圖,很直觀的說。x0dx0a 下面的方法,有助於將死鎖減至最少(詳細情況,請看SQLServer聯機幫助,搜索:將死鎖減至最少即可。x0dx0a按同一順序訪問對象。 x0dx0a避免事務中的用戶交互。 x0dx0a保持事務簡短並處於一個批處理中。 x0dx0a使用較低的隔離級別。 x0dx0a使用基於行版本控制的隔離級別。 x0dx0a將 READ_COMMITTED_SNAPSHOT 資料庫選項設置為 ON,使得已提交讀事務使用行版本控制。 x0dx0a使用快照隔離。x0dx0a使用綁定連接。

⑼ SQL頻繁的訪問一張資料庫表,如何避免死鎖如何提高性能

事務不能開太多,及時提交,因為事務沒有提交時,其他程序是不能對表進行更新操作,降低了資料庫的性能。涉及到大量數據的插入和更新是建議使用批量更新的方法。查詢提高性能的方法是瞎隱給作為磨磨廳條件的欄位加索引,但是變長的漢字最好不要加索引,游改它不能提高查詢的效率,最好用聯表查詢,減少子查詢。一個表裡的索引不能多於4個,否則插入和更新的速度是很慢的。。。關於資料庫還有很多適用的技巧,在此拋磚引玉啦,呵呵