取得目前造成資料庫鎖定的源頭

摘要:取得目前造成資料庫鎖定的源頭

 

有時因為系統設計不良,或資料量龐大容易造成 查詢A 因為查詢B 而咬住,但查詢B 又真正的元兇,因為他可能是被查詢C 咬住,而C 也可能只是連鎖效應的一個中間者。

 

在管理工具可以透過"監視器(SQL2005~2008)" 或. "目前活動(SQL2000)" 觀察,到底兇手是哪位,但在系統發生連鎖效應時以上工具常常是打不開的,因為DB反應真的慢到爆。

 

附件的SP  , 是透過一些系統內建的sp 函式加工處理後,直接把肉粽串的頭抓出來,在上面工具卡住打不開時,以另外一種比較節約資源的方式把兇手抓出來。

 

通常這類的連鎖問題,當把帶頭的砍掉以後,其他後續的程序就會因為等待資源已經被釋出,自動就會解鎖。但在砍之前記得把帶頭大哥的SQL 內容記錄一下,看看後續是否需要做索引的調整或查詢語法的改善。如果只是單純kill 掉,因為系統的操作與運行,剛好又有使用者踩到這個地雷程式,那大哥可能又會從出江湖,帶頭作亂。


ps : SQL 2000 跟SQL2005 以上 ,內建sp 有些許差異。

 



-- For SQL 2000
USE [msdb]
GO

/****** Object:  StoredProcedure [dbo].[sp_GetLockSource]    Script Date: 11/01/2012 18:53:57 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


-- =============================================
-- Author:		rachen
-- Create date: 2012.11.01
-- Description:	取得資料鎖定的主要來源.
-- =============================================
CREATE PROCEDURE [dbo].[sp_GetLockSource]
AS
BEGIN

	set nocount on;

	create table #sp_who2 (
		[SPID] smallint null ,
		[Status] nvarchar(30) null ,
		[Login]	nvarchar(30) null ,
		[HostName] nvarchar(30) null ,	
		[BlkBy]	varchar(3000) null , /*CommandText*/
		[DBName] nvarchar(100) null ,	
		[Command] nvarchar(100) null ,
		[CPUTime] int null ,
		[DiskIO] int null ,
		[LastBatch]	varchar(30) null , /*IsLockSource*/
		[ProgramName] nvarchar(60) null ,
		[BlkBySPID] smallint null
	);
	/*把 sp_who2 的結果塞入 temp 表單 */
	insert into #sp_who2 exec sp_who2;

	/*將 [BlkBy]處理成數字,以利後續處理 */
	update #sp_who2 set [BlkBySPID] = convert(smallint,Replace(Rtrim(Ltrim(BlkBy)),'.','')) , [BlkBy] = '' , [LastBatch] = '0';

	declare @SPID smallint;
	declare @CommandText varchar(3000);
	declare @Handle binary(20);

	declare SPIDList cursor  for
		select distinct M.SPID
		from #sp_who2 M 
		join #sp_who2 D on M.SPID = D.BlkBySPID 
		where M.BlkBySPID = 0 or M.SPID = D.SPID;
	open SPIDList;

	while 1 = 1 begin

		fetch next from SPIDList into @SPID;
		if ( @@fetch_status <> 0 ) goto WhileEnd

		set @CommandText = null;
		set @Handle = (select top 1 sql_handle from master.dbo.sysprocesses where spid = @SPID);
		set @CommandText = (select top 1 convert(varchar(3000),[text]) from ::fn_get_sql(@Handle));
		update #sp_who2 set [BlkBy] = isnull(@CommandText,'') , [LastBatch] = 1 where [SPID] = @SPID;

	end

	WhileEnd:

	close SPIDList;
	deallocate SPIDList;

	select SPID, Status, Login , HostName , DBName , Command , CPUTime , DiskIO ,  ProgramName , BlkBySPID ,
		BlkBy [CommandText] , 
		LastBatch [IsLockSource]
	from #sp_who2
	where LastBatch = '1';

END


GO

 



 


--For SQL 2005~2008
USE [msdb]
GO

/****** Object:  StoredProcedure [dbo].[sp_GetLockSource]    Script Date: 11/01/2012 18:51:31 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


-- =============================================
-- Author:		rachen
-- Create date: 2012.11.01
-- Description:	取得資料鎖定的主要來源.
-- =============================================
Create PROCEDURE [dbo].[sp_GetLockSource]
AS
BEGIN

	set nocount on;

	create table #sp_who2 (
		[SPID] smallint null ,
		[Status] nvarchar(30) null ,
		[Login]	nvarchar(30) null ,
		[HostName] nvarchar(30) null ,	
		[BlkBy]	varchar(3000) null , /*CommandText*/
		[DBName] nvarchar(100) null ,	
		[Command] nvarchar(100) null ,
		[CPUTime] int null ,
		[DiskIO] int null ,
		[LastBatch]	varchar(30) null , /*IsLockSource*/
		[ProgramName] nvarchar(60) null ,
		[BlkBySPID] smallint null ,
		[request_id] int null
	);
	/*把 sp_who2 的結果塞入 temp 表單 */
	insert into #sp_who2 exec sp_who2;

	/*將 [BlkBy]處理成數字,以利後續處理 */
	update #sp_who2 set [BlkBySPID] = convert(smallint,Replace(Rtrim(Ltrim(BlkBy)),'.','')) , [BlkBy] = '' , [LastBatch] = '0';

	declare @SPID smallint;
	declare @CommandText varchar(3000);
	declare @Handle binary(20);

	declare SPIDList cursor  for
		select distinct M.SPID
		from #sp_who2 M 
		join #sp_who2 D on M.SPID = D.BlkBySPID 
		where M.BlkBySPID = 0 or M.SPID = D.SPID;
	open SPIDList;

	while 1 = 1 begin

		fetch next from SPIDList into @SPID;
		if ( @@fetch_status <> 0 ) goto WhileEnd

		set @CommandText = null;
		set @Handle = (select top 1 sql_handle from master.dbo.sysprocesses where spid = @SPID);
		set @CommandText = (select top 1 convert(varchar(3000),[text]) from ::fn_get_sql(@Handle));
		update #sp_who2 set [BlkBy] = isnull(@CommandText,'') , [LastBatch] = 1 where [SPID] = @SPID;

	end

	WhileEnd:	

	close SPIDList;
	deallocate SPIDList;

	select SPID, Status, Login , HostName , DBName , Command , CPUTime , DiskIO ,  ProgramName , BlkBySPID ,
		BlkBy [CommandText] , 
		LastBatch [IsLockSource]
	from #sp_who2
	where LastBatch = '1';

END


GO