鎖定並非壞事,它是資料庫為確保 ACID 一致性而實作的必要機制。問題在於過度鎖定、長時間持有、死結導致並發度下降。系統變慢時,首要任務是「看見」正在發生什麼鎖定。
| 欄位 | 意義 | 查詢對應系統表 |
|---|---|---|
| spid | 處理序識別碼(連線 ID) | 執行 sp_who @spid 取得登入、主機、程式資訊 |
| dbid | 資料庫 ID | SELECT name FROM master..sysdatabases WHERE dbid = ... |
| objid | 物件 ID(資料表、索引等) | SELECT name FROM sysobjects WHERE id = ... |
| indid | 索引 ID(0=堆積,1=叢集,>1=非叢集) | - |
| type | 鎖定類型(TAB, PAG, ROW, KEY, EXT 等) | - |
| resource | 資源描述(檔案:頁碼:列號 等) | - |
| mode | 鎖定模式(S, X, U, IS, IX, SIX, Sch-S, Sch-M) | - |
| status | GRANT / WAIT / CNVT(等待或轉換中) | - |
EXEC sp_lock;
若回傳數百列,尋找 status = 'WAIT' 或同一 spid 擁有大量鎖定的列。
SELECT spid, COUNT(*) AS lock_count
FROM master..syslockinfo
GROUP BY spid
ORDER BY lock_count DESC;
DBCC INPUTBUFFER();
-- 或使用更詳細的
SELECT text FROM sys.dm_exec_sql_text(
(SELECT sql_handle FROM sys.dm_exec_requests WHERE session_id = )
);
-- 找出阻塞者與被阻塞者
SELECT
blocking.session_id AS blocker_spid,
blocked.session_id AS victim_spid,
blocked.wait_type,
blocked.wait_time,
blocked.wait_resource,
sqltext.text AS blocker_sql
FROM sys.dm_exec_requests blocked
JOIN sys.dm_exec_requests blocking ON blocked.blocking_session_id = blocking.session_id
CROSS APPLY sys.dm_exec_sql_text(blocking.sql_handle) sqltext
WHERE blocked.blocking_session_id > 0;
sp_lock 並記錄至歷史表,趨勢分析鎖定熱點。掌握 sp_lock、DBCC INPUTBUFFER 與 DMV 聯合查詢,能快速定位阻塞源頭、識別長跑交易、預防死結。鎖定可見,效能可控。