上接 SQL SERVER 查詢性能優化——分析事務與鎖(一)
第二步,通過SQL語句分析鎖定情況
由於SQL SERVER 2008相比SQL SERVER 2005中的“活動監視器”有了比較大的改變,所以下而我們通過SQL語句進行分析,使用SQL語句進行分析需要通過SP_WHO、SP_WHO2、SP_LOCK等系統存儲過程、Master.sys.sysprocesses系統視圖,或從SQL 2005(2008)新提供的動態視圖管理(DMV)sys.dm_exec_session、sys.dm_tran_locks等獲取相關信息。
通過master.sys.sysprocesses 視圖找出最初鎖住資源及導致后面一連串進程被迫停止的等待源頭。
下面我們舉一個例子來具體說明,以下代碼在SQL SERVER 2005/2008中都可以使用:
--1.創建測試表
CREATE TABLE [dbo].[Book]( [bookid] [int] NOT NULL, [Name] [varchar](60) NULL, [category] [varchar](10) NULL, [numberofcopies] [int] NULL, [AuthorID] [int] NULL, CONSTRAINT [PK_Book] PRIMARY KEY CLUSTERED ( [bookid] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
INSERT [dbo].[Book] ([bookid], [Name], [category], [numberofcopies], [AuthorID]) VALUES (1, N'SQL 2008', N'MS', 4, 1) INSERT [dbo].[Book] ([bookid], [Name], [category], [numberofcopies], [AuthorID]) VALUES (2, N'SharePoint 2007', N'MS', 3, 2) INSERT [dbo].[Book] ([bookid], [Name], [category], [numberofcopies], [AuthorID]) VALUES (3, N'SharePoint 2010', N'MS', 5, 2) INSERT [dbo].[Book] ([bookid], [Name], [category], [numberofcopies], [AuthorID]) VALUES (5, N'DB2', N'IBM', 10, 3) INSERT [dbo].[Book] ([bookid], [Name], [category], [numberofcopies], [AuthorID]) VALUES (7, N'SQL 2012', N'MS', 7, 1) --2.測試示例
--列出最初鎖定資源,導致一連串其他進程被鎖住的起始源頭。
例一 if exists(select * from master.sys.sysprocesses where spid in (select blocked from master.sys.sysprocesses)) begin
---確定進程被鎖住的其他資源
select spid 進程,STATUS 狀態, 登錄帳號=SUBSTRING(SUSER_SNAME(sid),1,30) ,用戶機器名稱=SUBSTRING(hostname,1,12) ,是否被鎖住=convert(char(3),blocked) ,數據庫名稱=SUBSTRING(db_name(dbid),1,20),cmd 命令,waittype as 等待類型 ,last_batch 最后批處理時間,open_tran 未提交事務的數量 from master.sys.sysprocesses --列出鎖住別人(在別的進程中blocked字段中出現的值)但自己未被鎖住(blocked=0)
Where spid in (select blocked from master.sys.sysprocesses) and blocked=0
end
else
begin
select '沒有被鎖住的進程'
end
---接下來我們通過以下代碼來構造一條進程被另外一條進程鎖住的情況。
--例二
Use test Go
Begin tran
update book set Name='MS SQL 2008'
where bookid=1
---切換到另一個查詢界面,執行以下代碼
--例三
Use test Go
select * from Book where bookid=1
go
3. 在SQL SERVER 2005/2008中的Microsoft SQL Server Management Studio中打開一個新的查詢界面,執行 exec SP_LOCK。結果如下圖。
圖1
從圖1中可以觀察到兩個進程的相互作用,其中進程“53”要求模式為“獨占(X)”,已經被獲取允許“GRANT”;進程“56”要求模式為“共享(S)”正等候(WAIT)處理。
如上圖1中進程“56”(執行SELECT語句的查詢連接)被進程“53”(執行UPDATE語句的查詢連接)封鎖的現象,並從Book數據表鎖定可以看出是因為“獨占”鎖定某一條索引鍵值(要求類型為KEY),導致進程“56”放置共享鎖定(要求模式為“S”),而在等待狀態(要求狀態為WAIT)。
4. 在SQL SERVER 2005/2008中的Microsoft SQL Server Management Studio中打開一個新查詢界面,通過另外一條連接來執行程序代碼(例一),執行結果如下圖。
圖2
在上圖2中可以看出例二查詢代碼開啟事務之后,未關閉事務,因此狀態(status)為sleeping,但並未被其他進程鎖住(blk),所以“是否被鎖住”列的數據為0,沒有執行命令,也沒有等待某種資源。另外由於該查詢的數據庫連接是Test,所以數據庫名稱為Test。
5. 查詢sysprocesses系統視圖呈現有問題的交易的現象可能有許多種,但最常見的一種就是status字段等於sleeping,waittype字段等於0x0000,last_batch字段表示離最后一次批處理執行的時候已經有一段距離了,以及open_tran字段大於0。例如,直接執行代碼例二,這時事務已經開啟,但是遲遲沒有結束,就可能是程序沒有做好事務管理。
可以在在SQL SERVER 2005/2008中的Microsoft SQL Server Management Studio中打開一個新查詢界面中執行下面的語句,以查詢有問題的連接
select spid 進程,STATUS 狀態, 登錄帳號=SUBSTRING(SUSER_SNAME(sid),1,30) ,用戶機器名稱=SUBSTRING(hostname,1,12) ,是否被鎖住=convert(char(3),blocked) ,數據庫名稱=SUBSTRING(db_name(dbid),1,20),cmd 命令,waittype as 等待類型 ,last_batch 最后批處理時間,open_tran 未提交事務的數量 from master.sys.sysprocesses Where status='sleeping' and waittype=0x0000 and open_tran>0
如下圖。
圖3
status字段等於sleeping表示沒有指示符正在執行,waittype字段等於0x0000代表此連接沒有等待任何資源,last_batch字段表示最后一次SQL語句執行的時間,如果此時間離現在有一段時間了,以及open_tran字段大於0,就有問題了。一段時間過去了,沒有等待任何資源,也沒有執行任何SQL語句,那么為什么還要開啟事務?
除了上述查詢sysprocesses系統視圖之外,SQL SERVER 2005/2008 可以通過“sys.dm_tran_locks動態管理視圖”呈現目前使用中相關的鎖定信息。返回的每一條記錄都代表一個已經授權或等待授權的鎖定。在結果集的數據行中,主要分成“資源”與“請求”兩類,其字段分別以resource與request為前綴。資源群組描述已經鎖定或等待的資源,而請求群組則描述已經獲取或等待中的鎖定請求。
--例四
select t1.resource_type [資源鎖定類型],DB_NAME(resource_database_id) as 數據庫名 ,t1.resource_associated_entity_id 鎖定對象,t1.request_mode as 等待者請求的鎖定模式 ,t1.request_session_id 等待者SID ,t2.wait_duration_ms 等待時間 ,(select TEXT from sys.dm_exec_requests r cross apply sys.dm_exec_sql_text(r.sql_handle) where r.session_id=t1.request_session_id) as 等待者要執行的SQL ,(select SUBSTRING(qt.text,r.statement_start_offset/2+1, (case when r.statement_end_offset=-1 then DATALENGTH(qt.text) else r.statement_end_offset end -r.statement_start_offset)/2+1 ) from sys.dm_exec_requests r cross apply sys.dm_exec_sql_text(r.sql_handle)qt where r.session_id=t1.request_session_id) 等待者正要執行的語句 ,t2.blocking_session_id [鎖定者SID] ,(select TEXT from sys.sysprocesses p cross apply sys.dm_exec_sql_text(p.sql_handle) where p.spid=t2.blocking_session_id ) 鎖定者執行語句 from sys.dm_tran_locks t1,sys.dm_os_waiting_tasks t2 where t1.lock_owner_address=t2.resource_address
在Sql 2005 的TEST執行上面的代碼,結果如下圖。(這是針對Wbk_pde_list數據表)
圖4
在Sql 2008 的TEST數據庫上執行上面的代碼,結果如下圖。(這是針對BOOK數據表)
圖5
備注:
以上第二步是通過在Microsoft SQL Server Management Studio中執行代碼進行查詢與分析加鎖情況,而在SQL SERVER 2005中則可以通過Microsoft SQL Server Management Studio管理獲取相當多的信息,方便讓你決定當前應該采取什么樣步驟。
上而第二步中獲取的信息都可以在SQL SERVER 2005中通過Microsoft SQL Server Management Studio中的“活動監視器”獲取。
例如通過“活動監視器--》按對象分類的鎖”,下拉菜單中選擇相應的對象。(如下圖)