SQLServer的一次堵塞分析
SQLServer的一次堵塞分析
今天工作人員突然報(bào)告說(shuō)某個(gè)界面無(wú)法正常打開(kāi)了,***個(gè)想到的便是SQLServer又發(fā)生堵塞了。在SQLServer中,做了一個(gè)5分鐘運(yùn)行一次的定時(shí)任務(wù),定期掃描堵塞情況;不過(guò)五分鐘有些太久了。就運(yùn)行了一下查詢(xún)堵塞的腳本,看看目前系統(tǒng)里正在發(fā)生的堵塞情況。
SELECT
blocked_query.session_id AS blocked_session_id,
blocking_query.session_id AS blocking_session_id,
blocking_sql_text.text AS blocking_sql_text,
blocked_sql_text.text AS blocked_sql_text,
waits.wait_type AS blocking_resource,
blocked_query.command AS blocked_command,
blocking_query.command AS blocking_command,
blocked_query.wait_type AS blocked_wait_type,
blocked_query.wait_time AS blocked_wait_time,
blocking_query.total_elapsed_time AS blocking_elapsed_time,
GETDATE()
FROM sys.dm_exec_requests blocked_query
JOIN sys.dm_exec_requests blocking_query ON
blocked_query.blocking_session_id = blocking_query.session_id
CROSS APPLY
(
SELECT *
FROM sys.dm_exec_sql_text(blocking_query.sql_handle)
) blocking_sql_text
CROSS APPLY
(
SELECT *
FROM sys.dm_exec_sql_text(blocked_query.sql_handle)
) blocked_sql_text
JOIN sys.dm_os_waiting_tasks waits ON
waits.session_id = blocking_query.session_id
查詢(xún)結(jié)果很簡(jiǎn)單,
被堵塞的是一個(gè)select語(yǔ)句,堵塞的是一個(gè)觸發(fā)器;兩者操作的是同一個(gè)表,blocking_resource為L(zhǎng)CK_M_S,很明顯是一個(gè)讀寫(xiě)的相互堵塞。
分析步驟理應(yīng)優(yōu)先從堵塞進(jìn)程開(kāi)始分析,然后再分析select語(yǔ)句
觸發(fā)器的業(yè)務(wù)邏輯比較復(fù)雜,大概有600多行,其中有一二十個(gè)select、update語(yǔ)句
只能按順序一個(gè)個(gè)來(lái)分析相關(guān)的select和update語(yǔ)句了,看看哪條sql可能出了問(wèn)題
主要是看SQL的where條件是否滿(mǎn)足索引和高選擇性要求,很快便定位到一條sql語(yǔ)句
SELECT *** @var1=field1 FROM tablename WHERE field2=@var2 AND field1 IS NOT NULL AND primarykey<>@primarykey
該表將近10萬(wàn)條記錄,而執(zhí)行該查詢(xún),等待了1分鐘卻看不到執(zhí)行結(jié)果。理論上是不應(yīng)該的,先標(biāo)記下來(lái)吧,繼續(xù)往下跟蹤。
很快又發(fā)現(xiàn)一條帶數(shù)據(jù)庫(kù)鏈接的查詢(xún)
SELECT *** primarykey FROM DBLINK.DBNAME.USERNAME.tablename WHERE COND1
先試著運(yùn)行一下吧,該SQL也是半天沒(méi)有響應(yīng)。
問(wèn)題應(yīng)該出現(xiàn)在這兩個(gè)地方,需要再了解一下相應(yīng)的業(yè)務(wù)邏輯再進(jìn)行SQL優(yōu)化,當(dāng)務(wù)之急是先把該session殺掉
運(yùn)行kill sessionid后,卻還是無(wú)法打開(kāi)程序界面,繼續(xù)運(yùn)行查詢(xún)堵塞腳本,發(fā)現(xiàn)blocking_command變成了KILLED/ROLLBACK,也就是說(shuō)一直處于rollback狀態(tài),沒(méi)有殺成功,很奇怪。而且整個(gè)數(shù)據(jù)庫(kù)似乎已經(jīng)全部癱瘓了,所有應(yīng)用程序均無(wú)法執(zhí)行。
于是系統(tǒng)工程師就把數(shù)據(jù)庫(kù)重啟了一下,又重新打開(kāi)該程序界面進(jìn)行數(shù)據(jù)處理,結(jié)果很快又出現(xiàn)之前的癥狀。
后來(lái)想是不是DBLINK出現(xiàn)了問(wèn)題,繼續(xù)運(yùn)行基于該DBLINK的查詢(xún)?cè)囈幌?,發(fā)現(xiàn)基本上全部無(wú)法執(zhí)行;還是先檢查一下網(wǎng)絡(luò)吧
系統(tǒng)工程師登陸到服務(wù)器上查看windows的日志,果然發(fā)現(xiàn)了很多網(wǎng)絡(luò)故障,緊急處理一下網(wǎng)絡(luò)。
再次運(yùn)行查詢(xún)堵塞腳本,發(fā)現(xiàn)堵塞已經(jīng)自動(dòng)消除,而那條看似很慢的SQL也很快運(yùn)行出結(jié)果了。
至此堵塞問(wèn)題已解決。
鑒于SQLServer的鎖的隔離機(jī)制被設(shè)置為READ_COMMITTED_SNAPSHOT,讀和寫(xiě)會(huì)導(dǎo)致沖突,問(wèn)題的根源也就不難理解了,但造成問(wèn)題的最終原因卻可能是多方面的。
這就是我要為大家介紹的關(guān)于SQLServer數(shù)據(jù)庫(kù)操作過(guò)程中堵塞問(wèn)題的解決方案,更多更好的方法還需要大家在以后的工作中善于總結(jié),希望上文中講到的內(nèi)容對(duì)大家能夠有所幫助。
【編輯推薦】