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

sql查詢語句發生死鎖的原因

發布時間: 2022-05-12 03:20:14

① 如何處理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,使得已提交讀事務使用行版本控制。
使用快照隔離。
使用綁定連接。

② 怎麼樣解決MSSQL產生死鎖的問題

一、 什麼是死鎖
死鎖是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去.此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等的進程稱為死鎖進程.

二、 死鎖產生的四個必要條件
互斥條件:指進程對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個進程佔用。如果此時還有其它進程請求資源,則請求者只能等待,直至佔有資源的進程用畢釋放
請求和保持條件:指進程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程佔有,此時請求進程阻塞,但又對自己已獲得的其它資源保持不放
不剝奪條件:指進程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放
環路等待條件:指在發生死鎖時,必然存在一個進程——資源的環形鏈,即進程集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1佔用的資源;P1正在等待P2佔用的資源,……,Pn正在等待已被P0佔用的資源
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖。
三、 如何處理死鎖
1) 鎖模式
共享鎖(S)
由讀操作創建的鎖,防止在讀取數據的過程中,其它事務對數據進行更新;其它事務可以並發讀取數據。共享鎖可以加在表、頁、索引鍵或者數據行上。在SQL SERVER默認隔離級別下數據讀取完畢後就會釋放共享鎖,但可以通過鎖提示或設置更高的事務隔離級別改變共享鎖的釋放時間。
2.獨占鎖(X)
對資源獨占的鎖,一個進程獨佔地鎖定了請求的數據源,那麼別的進程無法在此數據源上獲得任何類型的鎖。獨占鎖一致持有到事務結束。
3.更新鎖(U)
更新鎖實際上並不是一種獨立的鎖,而是共享鎖與獨占鎖的混合。當SQL SERVER執行數據修改操作卻首先需要搜索表以找到需要修改的資源時,會獲得更新鎖。
更新鎖與共享鎖兼容,但只有一個進程可以獲取當前數據源上的更新鎖,
其它進程無法獲取該資源的更新鎖或獨占鎖,更新鎖的作用就好像一個序列化閥門(serialization gate),將後續申請獨占鎖的請求壓入隊列中。持有更新鎖的進程能夠將其轉換成該資源上的獨占鎖。更新鎖不足以用於更新數據—實際的數據修改仍需要用到獨占鎖。對於獨占鎖的序列化訪問可以避免轉換死鎖的發生,更新鎖會保留到事務結束或者當它們轉換成獨占鎖時為止。
4. 意向鎖(IX,IU,IS)
意向鎖並不是獨立的鎖定模式,而是一種指出哪些資源已經被鎖定的機制。
如果一個表頁上存在獨占鎖,那麼另一個進程就無法獲得該表上的共享表鎖,這種層次關系是用意向鎖來實現的。進程要獲得獨占頁鎖、更新頁鎖或意向獨占頁鎖,首先必須獲得該表上的意向獨占鎖。同理,進程要獲得共享行鎖,必須首先獲得該表的意向共享鎖,以防止別的進程獲得獨占表鎖。
5. 特殊鎖模式(Sch_s,Sch_m,BU)
SQL SERVER提供3種額外的鎖模式:架構穩定鎖、架構修改鎖、大容量更新鎖。
6.轉換鎖(SIX,SIU,UIX)
轉換鎖不會由SQL SERVER 直接請求,而是從一種模式轉換到另一種模式所造成的。SQL SERVER 2008支持3種類型的轉換鎖:SIX、SIU、UIX.其中最常見的是SIX鎖,如果事務持有一個資源上的共享鎖(S),然後又需要一個IX鎖,此時就會出現SIX。
7.鍵范圍鎖
鍵范圍鎖是在可序列化隔離級別中鎖定一定范圍內數據的鎖。保證在查詢數據的鍵范圍內不允許插入數據。
http://www.cnblogs.com/qiaokai/p/5344252.html

③ mysql insert into select 語句為什麼會造成死鎖

對於MySQL來說,有三種鎖的級別:頁級、表級、行級

頁級的典型代表引擎為BDB。

表級的典型代表引擎為MyISAM,MEMORY以及很久以前的ISAM。

行級的典型代表引擎為INNODB。

-我們實際應用中用的最多的就是行鎖。

行級鎖的優點如下:

1)、當很多連接分別進行不同的查詢時減小LOCK狀態。

2)、如果出現異常,可以減少數據的丟失。因為一次可以只回滾一行或者幾行少量的數據。

行級鎖的缺點如下:

1)、比頁級鎖和表級鎖要佔用更多的內存。

2)、進行查詢時比頁級鎖和表級鎖需要的I/O要多,所以我們經常把行級鎖用在寫操作而不是讀操作。

3)、容易出現死鎖。

對於寫鎖定如下:

1)、如果表沒有加鎖,那麼對其加寫鎖定。

2)、否則,那麼把請求放入寫鎖隊列中。

對於讀鎖定如下:

1)、如果表沒有加寫鎖,那麼加一個讀鎖。

2)、否則,那麼把請求放到讀鎖隊列中。

當然我們可以分別用low_priority 以及high_priority在寫和讀操作上來改變這些行為。

如果想要在一個表上做大量的 INSERT 和 SELECT 操作,但是並行的插入卻不可能時,可以將記錄插入到臨時表中,然後定期將臨時表中的數據更新到實際的表裡。可以用以下命令實現:

mysql> LOCK TABLES real_table WRITE, insert_table WRITE;

mysql> INSERT INTO real_table SELECT * FROM insert_table;

mysql> TRUNCATE TABLE insert_table;

mysql> UNLOCK TABLES;

InnoDB 使用行級鎖,BDB 使用頁級鎖。對於 InnoDB 和 BDB 存儲引擎來說,是可能產生死鎖的。這是因為 InnoDB 會自動捕獲行鎖,BDB 會在執行 SQL 語句時捕獲頁鎖的,而不是在事務的開始就這么做。

行級鎖的優點有:

在很多線程請求不同記錄時減少沖突鎖。

事務回滾時減少改變數據。

使長時間對單獨的一行記錄加鎖成為可能。

行級鎖的缺點有:

比頁級鎖和表級鎖消耗更多的內存。

當在大量表中使用時,比頁級鎖和表級鎖更慢,因為他需要請求更多的所資源。

當需要頻繁對大部分數據做 GROUP BY 操作或者需要頻繁掃描整個表時,就明顯的比其它鎖更糟糕。

使用更高層的鎖的話,就能更方便的支持各種不同的類型應用程序,因為這種鎖的開銷比行級鎖小多了。

表級鎖在下列幾種情況下比頁級鎖和行級鎖更優越:

很多操作都是讀表。

在嚴格條件的索引上讀取和更新,當更新或者刪除可以用單獨的索引來讀取得到時:

UPDATE tbl_name SET column=value WHERE unique_key_col=key_value;

DELETE FROM tbl_name WHERE unique_key_col=key_value;

SELECT 和 INSERT 語句並發的執行,但是只有很少的 UPDATE 和 DELETE 語句。

很多的掃描表和對全表的 GROUP BY 操作,但是沒有任何寫表。

表級鎖和行級鎖或頁級鎖之間的不同之處還在於:

將同時有一個寫和多個讀的地方做版本(例如在MySQL中的並發插入)。也就是說,資料庫/表支持根據開始訪問數據時間點的不同支持各種不同的試圖。其它名有:時間行程,寫復制,或者是按需復制。

復制代碼 代碼如下:

//執行SQL語句 鎖掉stat_num表

$sql = "LOCK TABLES 表名 WRITE"; //表的WRITE鎖定,阻塞其他所有mysql查詢進程

mysql_query($sql);

//執行更新或寫入操作

$sql = "UPDATE stat_num SET `correct_num`=`correct_num`+1 WHERE stat_date='{$cur_date}'";

mysql_query($sql);

//當前請求的所有寫操作做完後,執行解鎖sql語句

$sql = "UNLOCK TABLES";

mysql_query($sql);

④ sql死鎖的原因及解決方法

在事務中在修改A表的時候沒有結束事務又要讀取A表的數據。導致自己等自己。變成死鎖。
解決方法很簡單,KILL掉就行。
程序上要先selet後update或者insert

⑤ 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操作。
發生死鎖的情況比較少,比如一個進程需要訪問兩個資源(資料庫表或者欄位),當獲取一個資源的時候進程就對它執行鎖定,然後等待下一個資源空閑,這時候如果另外一個進程也需要兩個資源,而已經獲得並鎖定了第二個資源,那麼就會死鎖,因為當前進程鎖定第一個資源等待第二個資源,而另外一個進程鎖定了第二個資源等待第一個資源,兩個進程都永遠得不到滿足。
資料庫死鎖的解決方案。
死鎖的預防和解除:
理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和解除死鎖。所以,在系統設計、進程調度等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配演算法,避免進程永久占據系統資源。此外,也要防止進程在處於等待狀態的情況下佔用資源,在系統運行過程中,對進程發出的每一個系統能夠滿足的資源申請進行動態檢查,並根據檢查結果決定是否分配資源,若分配後系統可能發生死鎖,則不予分配,否則予以分配 。因此,對資源的分配要給予合理的規劃。
如何將死鎖減至最少
雖然不能完全避免死鎖,但可以使死鎖的數量減至最少。將死鎖減至最少可以增加事務的吞吐量並減少系統開銷,因為只有很少的事務回滾,而回滾會取消事務執行的所有工作。由於死鎖時回滾而由應用程序重新提交。
下列方法有助於最大限度地降低死鎖:
(1)按同一順序訪問對象。
(2)避免事務中的用戶交互。
(3)保持事務簡短並在一個批處理中。
(4)使用低隔離級別。
(5)使用綁定連接。
按同一順序訪問對象
如果所有並發事務按同一順序訪問對象,則發生死鎖的可能性會降低。例如,如果兩個並發事務獲得 Supplier 表上的鎖,然後獲得 Part 表上的鎖,則在其中一個事務完成之前,另一個事務被阻塞在 Supplier 表上。第一個事務提交或回滾後,第二個事務繼續進行。不發生死鎖。將存儲過程用於所有的數據修改可以標准化訪問對象的順序。
避免事務中的用戶交互
避免編寫包含用戶交互的事務,因為運行沒有用戶交互的批處理的速度要遠遠快於用戶手動響應查詢的速度,例如答復應用程序請求參數的提示。例如,如果事務正在等待用戶輸入,而用戶去吃午餐了或者甚至回家過周末了,則用戶將此事務掛起使之不能完成。這樣將降低系統的吞吐量,因為事務持有的任何鎖只有在事務提交或回滾時才會釋放。即使不出現死鎖的情況,訪問同一資源的其它事務也會被阻塞,等待該事務完成。
保持事務簡短並在一個批處理中
在同一資料庫中並發執行多個需要長時間運行的事務時通常發生死鎖。事務運行時間越長,其持有排它鎖或更新鎖的時間也就越長,從而堵塞了其它活動並可能導致死鎖。
保持事務在一個批處理中,可以最小化事務的網路通信往返量,減少完成事務可能的延遲並釋放鎖。
使用低隔離級別
確定事務是否能在更低的隔離級別上運行。執行提交讀允許事務讀取另一個事務已讀取(未修改)的數據,而不必等待第一個事務完成。使用較低的隔離級別(例如提交讀)而不使用較高的隔離級別(例如可串列讀)可以縮短持有共享鎖的時間,從而降低了鎖定爭奪。
使用綁定連接
使用綁定連接使同一應用程序所打開的兩個或多個連接可以相互合作。次級連接所獲得的任何鎖可以象由主連接獲得的鎖那樣持有,反之亦然,因此不會相互阻塞。

⑦ sql資料庫一個表最近經常死鎖,改怎麼查詢死鎖原因

原因很多,比如事務未能提交或2表互相操作等等....

查找死鎖:
Select * from master..sysprocesses where blocked > 0
dbcc inputbuffer(spid)
用db_name(dbid)和object_name(objid)找到對應的庫+表,修改語句

⑧ 如何查看SQL死鎖

其實所有的死鎖最深層的原因就是一個:資源競爭
表現一:
一個用戶A
訪問表A(鎖住了表A),然後又訪問表B
另一個用戶B
訪問表B(鎖住了表B),然後企圖訪問表A
這時用戶A由於用戶B已經鎖住表B,它必須等待用戶B釋放表B,才能繼續,好了他老人家就只好老老實實在這等了
同樣用戶B要等用戶A釋放表A才能繼續這就死鎖了
解決方法:
這種死鎖是由於你的程序的BUG產生的,除了調整你的程序的邏輯別無他法
仔細分析你程序的邏輯,
1:盡量避免同時鎖定兩個資源
2:
必須同時鎖定兩個資源時,要保證在任何時刻都應該按照相同的順序來鎖定資源.
表現二:
用戶A讀一條紀錄,然後修改該條紀錄
這是用戶B修改該條紀錄
這里用戶A的事務里鎖的性質由共享鎖企圖上升到獨占鎖(for
update),而用戶B里的獨占鎖由於A有共享鎖存在所以必須等A釋
放掉共享鎖,而A由於B的獨占鎖而無法上升的獨占鎖也就不可能釋放共享鎖,於是出現了死鎖。
這種死鎖比較隱蔽,但其實在稍大點的項目中經常發生。
解決方法:
讓用戶A的事務(即先讀後寫類型的操作),在select
時就是用Update
lock
語法如下:
select
*
from
table1
with(updlock)
where
....

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

資料庫操作的死鎖是不可避免的,本文並不打算討論死鎖如何產生,重點在於解決死鎖,通過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資料庫總是假死或死鎖。

建議:
1、使用事件探查器,跟蹤一下SQL在死鎖之前執行了哪些SQL語句
2、多數死鎖是因為程序沒有經過嚴格的測試造成的
3、少部分原因是因為觸發器嵌套造成的,SQL有內部機制,當嵌套到一定的層級,就自動終止掉相關的進程
願早日解決問題