MySQL死鎖問題的相關知識是本文我們主要要介紹的內容,接下來我們就來一一介紹這部分內容,希望能夠對您有所幫助。
1、MySQL常用存儲引擎的鎖機制
MyISAM和MEMORY採用表級鎖(table-level locking)
BDB採用頁面鎖(page-level locking)或表級鎖,默認為頁面鎖
InnoDB支持行級鎖(row-level locking)和表級鎖,默認為行級鎖
2、各種鎖特點
表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低
行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高
頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並發度一般
3、各種鎖的適用場景
表級鎖更適合於以查詢為主,只有少量按索引條件更新數據的應用,如Web應用
行級鎖則更適合於有大量按索引條件並發更新數據,同時又有並發查詢的應用,如一些在線事務處理系統
4、死鎖
是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。
表級鎖不會產生死鎖。所以解決死鎖主要還是針對於最常用的InnoDB。
5、死鎖舉例分析
在MySQL中,行級鎖並不是直接鎖記錄,而是鎖索引。索引分為主鍵索引和非主鍵索引兩種,如果一條sql語句操作了主鍵索引,MySQL就會鎖定這條主鍵索引;如果一條語句操作了非主鍵索引,MySQL會先鎖定該非主鍵索引,再鎖定相關的主鍵索引。
在UPDATE、DELETE操作時,MySQL不僅鎖定WHERE條件掃描過的所有索引記錄,而且會鎖定相鄰的鍵值,即所謂的next-key locking。
例如,一個表db。tab_test,結構如下:
id:主鍵;
state:狀態;
time:時間;
索引:idx_1(state,time)
出現死鎖日誌如下:
?***(1) TRANSACTION:
?TRANSACTION 0 677833455, ACTIVE 0 sec, process no 11393, OSthread id 278546 starting index read
?mysql tables in use 1, locked 1
?LOCK WAIT 3 lock struct(s), heap size 320
?MySQL thread id 83, query id 162348740 dcnet03 dcnet Searching rows for update
?update tab_test set state=1064,time=now() where state=1061 and time < date_sub(now(), INTERVAL 30 minute) (任務1的sql語句)
?***(1) WAITING FOR THIS LOCK TO BE GRANTED: (任務1等待的索引記錄)
?RECORD LOCKS space id 0 page no 849384 n bits 208 index `PRIMARY` of table `db/tab_test` trx id 0 677833455 _mode X locks rec but not gap waiting
?Record lock, heap no 92 PHYSICAL RECORD: n_fields 11; compact format; info bits 0
?0: len 8; hex 800000000097629c; asc b ;; 1: len 6; hex 00002866eaee; asc (f ;; 2: len 7; hex 00000d40040110; asc @ ;; 3: len 8; hex 80000000000050b2; asc P ;; 4: len 8; hex 800000000000502a; asc P*;; 5: len 8; hex 8000000000005426; asc T&;; 6: len 8; hex 800012412c66d29c; asc A,f ;; 7: len 23; hex 8616e642e706870; asc xxx.com/;; 8: len 8; hex 800000000000042b; asc +;; 9: len 4; hex 474bfa2b; asc GK +;; 10: len 8; hex 8000000000004e24; asc N$;;
?*** (2) TRANSACTION:
?TRANSACTION 0 677833454, ACTIVE 0 sec, process no 11397, OS thread id 344086 updating or deleting, thread declared inside InnoDB 499
?mysql tables in use 1, locked 1
?3 lock struct(s), heap size 320, undo log entries 1
?MySQL thread id 84, query id 162348739 dcnet03 dcnet Updating update tab_test set state=1067,time=now () where id in (9921180) (任務2的sql語句)
?*** (2) HOLDS THE LOCK(S): (任務2已獲得的鎖)
?RECORD LOCKS space id 0 page no 849384 n bits 208 index `PRIMARY` of table `db/tab_test` trx id 0 677833454 lock_mode X locks rec but not gap
?Record lock, heap no 92 PHYSICAL RECORD: n_fields 11; compact format; info bits 0
?0: len 8; hex 800000000097629c; asc b ;; 1: len 6; hex 00002866eaee; asc (f ;; 2: len 7; hex 00000d40040110; asc @ ;; 3: len 8; hex 80000000000050b2; asc P ;; 4: len 8; hex 800000000000502a; asc P*;; 5: len 8; hex 8000000000005426; asc T&;; 6: len 8; hex 800012412c66d29c; asc A,f ;; 7: len 23; hex 8616e642e706870; asc uploadfire.com/hand.php;; 8: len 8; hex 800000000000042b; asc +;; 9: len 4; hex 474bfa2b; asc GK +;; 10: len 8; hex 8000000000004e24; asc N$;;
?*** (2) WAITING FOR THIS LOCK TO BE GRANTED: (任務2等待的鎖)
?RECORD LOCKS space id 0 page no 843102 n bits 600 index `idx_1` of table `db/tab_test` trx id 0 677833454 lock_mode X locks rec but not gap waiting
?Record lock, heap no 395 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
?0: len 8; hex 8000000000000425; asc %;; 1: len 8; hex 800012412c66d29c; asc A,f ;; 2: len 8; hex 800000000097629c; asc b ;;
?*** WE ROLL BACK TRANSACTION (1)
?(回滾了任務1,以解除死鎖)
原因分析:
當「update tab_test set state=1064,time=now() where state=1061 and time < date_sub(now(), INTERVAL 30 minute)」執行時,MySQL會使用idx_1索引,因此首先鎖定相關的索引記錄,因為idx_1是非主鍵索引,為執行該語句,MySQL還會鎖定主鍵索引。
假設「update tab_test set state=1067,time=now () where id in (9921180)」幾乎同時執行時,本語句首先鎖定主鍵索引,由於需要更新state的值,所以還需要鎖定idx_1的某些索引記錄。
這樣第一條語句鎖定了idx_1的記錄,等待主鍵索引,而第二條語句則鎖定了主鍵索引記錄,而等待idx_1的記錄,這樣死鎖就產生了。
6、解決辦法
拆分第一條sql,先查出符合條件的主鍵值,再按照主鍵更新記錄:
?select id from tab_test where state=1061 and time < date_sub(now(), INTERVAL 30 minute);
?update tab_test state=1064,time=now() where id in(......);
Ⅱ 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,我增經試過被鎖住,找了很久才知
Ⅲ sqldeveloper怎麼殺死死鎖的表
嘗試在sqlplus中通過sql命令進行刪除,如果能夠刪除成功,則萬事大吉。
但通常情況下,出現死鎖時,想通過命令行或者通過oracle的管理工具刪除有死鎖的session,oracle只會將該session標記為killed,但無法清除掉,往往需要通過第二步在操作系統層級進行刪除。
altersystemkillsession29,57107。--刪除進程,如已經刪除過,則會報ora-00031的錯誤,否則oracle會將該session標記為killed狀態,等待一段時間看能否會自動消失,如長時間消失不掉,則需要做後續步驟。一些ORACLE中的進程被殺掉後,狀態被置為killed,但是鎖定的資源很長時間不釋放,有時實在沒辦法,只好重啟資料庫。現在提供一種方法解決這種問題,那就是在ORACLE中殺不掉的,在OS一級再殺。
Ⅳ sql死鎖的原因及解決方法
在事務中在修改A表的時候沒有結束事務又要讀取A表的數據。導致自己等自己。變成死鎖。
解決方法很簡單,KILL掉就行。
程序上要先selet後update或者insert
Ⅳ sqlserver怎麼清除死鎖
查詢語句的表名後加(nolock)少用臨時表和group by HAVING。
Ⅵ sql死鎖怎麼解決,幫幫忙!
這個以前是在網上看到的你可以試試
運行時錯誤:-2147217900(80040e14)
SqlDumpExceptionHandler:進程53發生嚴重的異常c0000005 EXCEPTION_ACCESS_VIOLATION.SQL Server將終止進程
運行時錯誤 -2147467259(80004005)
事務(進程ID 63)與另一個進程已被鎖在 LOCK 資源上,且該事務已被選作死鎖犧牲品。請重新運行該事物
1. 用下面的語句檢查表是否有問題, 如果有, 按檢查的結果提示修復
use 你的庫名
dbcc checktable('vw_T_Dept')
2. 重建索引
dbcc dbreindex('vw_T_Dept')
Ⅶ sql 怎麼手動殺死死鎖進程
用kill命令,殺進程。