sqlserver死鎖查詢
死鎖檢測
use master
Select * from sysprocesses where blocked<>0
--找到SPID
exec sp_lock
--根據SPID找到OBJID
select object_name(85575343)
--根據OBJID找到表名
2. 如何處理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使用綁定連接。
3. 如何監控sqlserver 性能 死鎖
具體步驟如下:
1.首先使用下面的命令,將有關的跟蹤標志啟用。
SQL codeDBCC TRACEON (3605,1204,1222,-1)
說明:
3605
將DBCC的結果輸出到錯誤日誌。
1204 返回參與死鎖的鎖的資源和類型,以及受影響的當前命令。
1222
返回參與死鎖的鎖的資源和類型,以及使用了不符合任何 XSD 架構的 XML 格式的受影響的當前命令(比1204更進一步,SQL
2005及以上可用)。
-1 以全局方式打開指定的跟蹤標記。
以上跟蹤標志作用域都是全局,即在SQL
Server運行過程中,會一直發揮作用,直到SQL Server重啟。
如 果要確保SQL Server在重啟後自動開啟這些標志,可以在SQL
Server服務啟動選項中,使用 /T 啟動選項指定跟蹤標志在啟動期
間設置為開。(位於SQL Server配置管理器->SQL
Server服務->SQL Server->屬性->高級->啟動參數)
在運行上面的語句後,當SQL
Server中發生死鎖時,已經可以在錯誤日誌中看到了,但還不夠直觀(和其它信息混在一起)。(SSMS
-> SQL Server實例 ->
管理 -> SQL Server日誌)
2.建表,存放死鎖記錄
SQL codeUSE [Cole] --Cole是我的示例資料庫,你可以根據實際情況修改。 GO
CREATE TABLE DeadLockLog ( id int IDENTITY (1, 1) NOT NULL, LogDate DATETIME, ProcessInfo VARCHAR(10), ErrorText VARCHAR(MAX) )
GO
3.建立JOB
新建一個JOB(假設名稱為DeadLockJob),在"步驟"中新建一步驟,隨便寫一個步驟名稱,資料庫為"Cole",在"命令"欄中輸入以下語句:
SQL code--新建臨時表 IF OBJECT_ID('tempdb.dbo.#ErrorLog') IS Not Null
DROP TABLE #ErrorLog
CREATE TABLE #ErrorLog (Id int IDENTITY (1, 1) NOT NULL, a DATETIME, b VARCHAR(10), c VARCHAR(MAX)) --將當前日誌記錄插入臨時表
INSERT INTO #ErrorLog EXEC master.dbo.sp_readerrorlog --將死鎖信息插入用戶表
insert DeadLockLog
select a, b, c from #ErrorLog where id >= (select MAX(id) from #ErrorLog WHERE c Like '%Deadlock encountered%')
DROP TABLE #ErrorLog
4.新建警報
在"新建警報"窗體的"常規"選項卡中,進行以下設置:
名稱:可根據實際自行命名,這里我用DeadLockAlert
類型:選擇"SQL
Server性能條件警報"
對象:SQLServer:Locks
計數器:Number of
Deadlocks/sec
實例:_Total
計數器滿足以下條件時觸發警報:高於
值:0
在"響應"選項卡中,選中"執行作業",並選擇步驟3中我們新建的作業(即DeadlockJob)
到這里為止,我們已經完成了全部步驟,以後,你就可以隨時查詢DeadLockLog表,來顯示死鎖信息了。
4. 如何處理SQL Server死鎖問題
死鎖,簡而言之,兩個或者多個trans,同時請求對方正在請求的某個對象,導致雙方互相等待。簡單的例子如下:
trans1 trans2
------------------------------------------------------------------------
1.IDBConnection.BeginTransaction 1.IDBConnection.BeginTransaction
2.update table A 2.update table B
3.update table B 3.update table A
4.IDBConnection.Commit 4.IDBConnection.Commit
那麼,很容易看到,如果trans1和trans2,分別到達了step3,那麼trans1會請求對於B的X鎖,trans2會請求對於A的X鎖,而二者的鎖在step2上已經被對方分別持有了。由於得不到鎖,後面的Commit無法執行,這樣雙方開始死鎖。
好,我們看一個簡單的例子,來解釋一下,應該如何解決死鎖問題。
-- Batch #1
CREATE DATABASE deadlocktest
GO
USE deadlocktest
SET NOCOUNT ON
DBCC TRACEON (1222, -1)
-- 在SQL2005中,增加了一個新的dbcc參數,就是1222,原來在2000下,我們知道,可以執行dbcc
--traceon(1204,3605,-1)看到所有的死鎖信息。SqlServer 2005中,對於1204進行了增強,這就是1222。
GO
IF OBJECT_ID ('t1') IS NOT NULL DROP TABLE t1
IF OBJECT_ID ('p1') IS NOT NULL DROP PROC p1
IF OBJECT_ID ('p2') IS NOT NULL DROP PROC p2
GO
CREATE TABLE t1 (c1 int, c2 int, c3 int, c4 char(5000))
GO
DECLARE @x int
SET @x = 1
WHILE (@x <= 1000) BEGIN
INSERT INTO t1 VALUES (@x*2, @x*2, @x*2, @x*2)
SET @x = @x + 1
END
GO
CREATE CLUSTERED INDEX cidx ON t1 (c1)
CREATE NONCLUSTERED INDEX idx1 ON t1 (c2)
GO
CREATE PROC p1 @p1 int AS SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+1
GO
CREATE PROC p2 @p1 int AS
UPDATE t1 SET c2 = c2+1 WHERE c1 = @p1
UPDATE t1 SET c2 = c2-1 WHERE c1 = @p1
GO
上述sql創建一個deadlock的示範資料庫,插入了1000條數據,並在表t1上建立了c1列的聚集索引,和c2列的非聚集索引。另外創建了兩個sp,分別是從t1中select數據和update數據。
好,打開一個新的查詢窗口,我們開始執行下面的query:
-- Batch #2
USE deadlocktest
SET NOCOUNT ON
WHILE (1=1) EXEC p2 4
GO
開始執行後,然後我們打開第三個查詢窗口,執行下面的query:
-- Batch #3
USE deadlocktest
SET NOCOUNT ON
CREATE TABLE #t1 (c2 int, c3 int)
GO
WHILE (1=1) BEGIN
INSERT INTO #t1 EXEC p1 4
TRUNCATE TABLE #t1
END
GO
開始執行,哈哈,很快,我們看到了這樣的錯誤信息:
Msg 1205, Level 13, State 51, Procere p1, Line 4
Transaction (Process ID 54) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
spid54發現了死鎖。
那麼,我們該如何解決它?
在SqlServer 2005中,我們可以這么做:
1.在trans3的窗口中,選擇EXEC p1 4,然後right click,看到了菜單了嗎?選擇Analyse Query in Database Engine Tuning Advisor。
2.注意右面的窗口中,wordload有三個選擇:負載文件、表、查詢語句,因為我們選擇了查詢語句的方式,所以就不需要修改這個radio option了。
3.點左上角的Start Analysis按鈕
4.抽根煙,回來後看結果吧!出現了一個分析結果窗口,其中,在Index Recommendations中,我們發現了一條信息:大意是,在表t1上增加一個非聚集索引索引:t2+t1。
5.在當前窗口的上方菜單上,選擇Action菜單,選擇Apply Recommendations,系統會自動創建這個索引。
重新運行batch #3,呵呵,死鎖沒有了。
這種方式,我們可以解決大部分的Sql Server死鎖問題。那麼,發生這個死鎖的根本原因是什麼呢?為什麼增加一個non clustered index,問題就解決了呢? 這次,我們分析一下,為什麼會死鎖呢?再回顧一下兩個sp的寫法:
CREATE PROC p1 @p1 int AS
SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+1
GO
CREATE PROC p2 @p1 int AS
UPDATE t1 SET c2 = c2+1 WHERE c1 = @p1
UPDATE t1 SET c2 = c2-1 WHERE c1 = @p1
GO
很奇怪吧!p1沒有insert,沒有delete,沒有update,只是一個select,p2才是update。這個和我們前面說過的,trans1裡面updata A,update B;trans2裡面upate B,update A,根本不貼邊啊!
那麼,什麼導致了死鎖?
需要從事件日誌中,看sql的死鎖信息:
Spid X is running this query (line 2 of proc [p1], inputbuffer 「… EXEC p1 4 …」):
SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+1
Spid Y is running this query (line 2 of proc [p2], inputbuffer 「EXEC p2 4」):
UPDATE t1 SET c2 = c2+1 WHERE c1 = @p1
The SELECT is waiting for a Shared KEY lock on index t1.cidx. The UPDATE holds a conflicting X lock.
The UPDATE is waiting for an eXclusive KEY lock on index t1.idx1. The SELECT holds a conflicting S lock.
首先,我們看看p1的執行計劃。怎麼看呢?可以執行set statistics profile on,這句就可以了。下面是p1的執行計劃
SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+1
|--Nested Loops(Inner Join, OUTER REFERENCES:([Uniq1002], [t1].[c1]))
|--Index Seek(OBJECT:([t1].[idx1]), SEEK:([t1].[c2] >= [@p1] AND [t1].[c2] <= [@p1]+(1)) ORDERED FORWARD)
|--Clustered Index Seek(OBJECT:([t1].[cidx]), SEEK:([t1].[c1]=[t1].[c1] AND [Uniq1002]=[Uniq1002]) LOOKUP ORDERED FORWARD)
我們看到了一個nested loops,第一行,利用索引t1.c2來進行seek,seek出來的那個rowid,在第二行中,用來通過聚集索引來查找整行的數據。這是什麼?就是bookmark lookup啊!為什麼?因為我們需要的c2、c3不能完全的被索引t1.c1帶出來,所以需要書簽查找。
好,我們接著看p2的執行計劃。
UPDATE t1 SET c2 = c2+1 WHERE c1 = @p1
|--Clustered Index Update(OBJECT:([t1].[cidx]), OBJECT:([t1].[idx1]), SET:([t1].[c2] = [Expr1004]))
|--Compute Scalar(DEFINE:([Expr1013]=[Expr1013]))
|--Compute Scalar(DEFINE:([Expr1004]=[t1].[c2]+(1), [Expr1013]=CASE WHEN CASE WHEN ...
|--Top(ROWCOUNT est 0)
|--Clustered Index Seek(OBJECT:([t1].[cidx]), SEEK:([t1].[c1]=[@p1]) ORDERED FORWARD)
通過聚集索引的seek找到了一行,然後開始更新。這里注意的是,update的時候,它會申請一個針對clustered index的X鎖的。
實際上到這里,我們就明白了為什麼update會對select產生死鎖。update的時候,會申請一個針對clustered index的X鎖,這樣就阻塞住了(注意,不是死鎖!)select裡面最後的那個clustered index seek。死鎖的另一半在哪裡呢?注意我們的select語句,c2存在於索引idx1中,c1是一個聚集索引cidx。問題就在這里!我們在p2中更新了c2這個值,所以sqlserver會自動更新包含c2列的非聚集索引:idx1。而idx1在哪裡?就在我們剛才的select語句中。而對這個索引列的更改,意味著索引集合的某個行或者某些行,需要重新排列,而重新排列,需要一個X鎖。
SO………,問題就這樣被發現了。
總結一下,就是說,某個query使用非聚集索引來select數據,那麼它會在非聚集索引上持有一個S鎖。當有一些select的列不在該索引上,它需要根據rowid找到對應的聚集索引的那行,然後找到其他數據。而此時,第二個的查詢中,update正在聚集索引上忙乎:定位、加鎖、修改等。但因為正在修改的某個列,是另外一個非聚集索引的某個列,所以此時,它需要同時更改那個非聚集索引的信息,這就需要在那個非聚集索引上,加第二個X鎖。select開始等待update的X鎖,update開始等待select的S鎖,死鎖,就這樣發生鳥。
那麼,為什麼我們增加了一個非聚集索引,死鎖就消失鳥?我們看一下,按照上文中自動增加的索引之後的執行計劃:
SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+1
|--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)
哦,對於clustered index的需求沒有了,因為增加的覆蓋索引已經足夠把所有的信息都select出來。就這么簡單。
實際上,在sqlserver 2005中,如果用profiler來抓eventid:1222,那麼會出現一個死鎖的圖,很直觀的說。
下面的方法,有助於將死鎖減至最少(詳細情況,請看SQLServer聯機幫助,搜索:將死鎖減至最少即可。
按同一順序訪問對象。
避免事務中的用戶交互。
保持事務簡短並處於一個批處理中。
使用較低的隔離級別。
使用基於行版本控制的隔離級別。
將 READ_COMMITTED_SNAPSHOT 資料庫選項設置為 ON,使得已提交讀事務使用行版本控制。
使用快照隔離。
使用綁定連接。
5. sqlserver怎麼用sql查看具體那個表被鎖住了
詳細步驟如下:
1、點擊【新建查詢】按鈕,打開SQL命令編輯框,對資料庫表的操作以及維護都可以通過編輯SQL命令實現。
3、創建數據表的源代碼如下:
use test go
if exists(select name from sys.tables where name='Student')
drop table Student go
create table Student
(sname nchar(10) primary key,
sex nchar(2) not null,
bir datetime)
6. sqlserver怎麼清除死鎖
1、首先需要判斷是哪個用戶鎖住了哪張表.
查詢被鎖表
selectrequest_session_idspid,OBJECT_NAME(resource_associated_entity_id)tableName
fromsys.dm_tran_lockswhereresource_type='OBJECT'
查詢後會返回一個包含spid和tableName列的表.
其中spid是進程名,tableName是表名.
2.了解到了究竟是哪個進程鎖了哪張表後,需要通過進程找到鎖表的主機.
查詢主機名
execsp_who2'xxx'
xxx就是spid列的進程,檢索後會列出很多信息,其中就包含主機名.
3.通過spid列的值進行關閉進程.
關閉進程
declare@spidint
Set@spid=xxx--鎖表進程
declare@sqlvarchar(1000)
set@sql='kill'+cast(@spidasvarchar)
exec(@sql)
PS:有些時候強行殺掉進程是比較危險的,所以最好可以找到執行進程的主機,在該機器上關閉進程.