如何找到锁定我的表的内容

时间:2012-01-05 20:36:50

标签: sql sql-server locking

我有一个SQL表突然无法返回数据,除非我在末尾包含“with(nolock)”,这表示我的表上还有某种锁。我已经用dm_tran_locks进行了一些实验,以确定表上实际上存在多个锁,但是如何识别 锁定它们的是什么(即dm_tran_locks的请求元素)? / p> 编辑:我知道SQL 2005之前的sp_lock,但是现在不推荐使用sp,AFAIK正确的做法是使用dm_tran_locks。我正在使用SQL Server 2008 R2。

9 个答案:

答案 0 :(得分:49)

查看以下系统存储过程,您可以在SQLServer Management Studio(SSMS)中运行:

  • sp_who的
  • sp_lock的

此外,在SSMS中,您可以通过不同方式查看锁和进程:

enter image description here

不同版本的SSMS将活动监视器放在不同的位置。例如,当您右键单击服务器节点时,SSMS 2008和2012会在上下文菜单中显示它。

答案 1 :(得分:48)

为了直接“阻止/阻止谁”我将sp_who和sp_lock组合/缩写为单个查询,这可以很好地概述谁将哪个对象锁定到什么级别。

--Create Procedure WhoLock
--AS
set nocount on
if object_id('tempdb..#locksummary') is not null Drop table #locksummary
if object_id('tempdb..#lock') is not null Drop table #lock
create table #lock (    spid int,    dbid int,    objId int,    indId int,    Type char(4),    resource nchar(32),    Mode char(8),    status char(6))
Insert into #lock exec sp_lock
if object_id('tempdb..#who') is not null Drop table #who
create table #who (     spid int, ecid int, status char(30),
            loginame char(128), hostname char(128),
            blk char(5), dbname char(128), cmd char(16)
            --
            , request_id INT --Needed for SQL 2008 onwards
            --
         )
Insert into #who exec sp_who
Print '-----------------------------------------'
Print 'Lock Summary for ' + @@servername  + ' (excluding tempdb):'
Print '-----------------------------------------' + Char(10)
Select     left(loginame, 28) as loginame, 
    left(db_name(dbid),128) as DB,
    left(object_name(objID),30) as object,
    max(mode) as [ToLevel],
    Count(*) as [How Many],
    Max(Case When mode= 'X' Then cmd Else null End) as [Xclusive lock for command],
    l.spid, hostname
into #LockSummary
from #lock l join #who w on l.spid= w.spid
where dbID != db_id('tempdb') and l.status='GRANT'
group by dbID, objID, l.spid, hostname, loginame

Select * from #LockSummary order by [ToLevel] Desc, [How Many] Desc, loginame, DB, object

Print '--------'
Print 'Who is blocking:'
Print '--------' + char(10)
SELECT p.spid
,convert(char(12), d.name) db_name
, program_name
, p.loginame
, convert(char(12), hostname) hostname
, cmd
, p.status
, p.blocked
, login_time
, last_batch
, p.spid
FROM      master..sysprocesses p
JOIN      master..sysdatabases d ON p.dbid =  d.dbid
WHERE     EXISTS (  SELECT 1
          FROM      master..sysprocesses p2
          WHERE     p2.blocked = p.spid )

Print '--------'
Print 'Details:'
Print '--------' + char(10)
Select     left(loginame, 30) as loginame,  l.spid,
    left(db_name(dbid),15) as DB,
    left(object_name(objID),40) as object,
    mode ,
    blk,
    l.status
from #lock l join #who w on l.spid= w.spid
where dbID != db_id('tempdb') and blk <>0
Order by mode desc, blk, loginame, dbID, objID, l.status

(对于锁定级别缩写的含义,请参阅例如https://technet.microsoft.com/en-us/library/ms175519%28v=sql.105%29.aspx

复制自:sp_WhoLock – a T-SQL stored proc combining sp_who and sp_lock...

注意[命令的Xclusive lock]列可能会产生误导 - 它会显示该spid的当前命令;但是X锁可能是由事务中的早期命令触发的。

答案 2 :(得分:12)

我有一个存储过程,我将它放在一起,不仅可以处理锁定和阻塞,还可以查看服务器中正在运行的内容。 我把它放在主人的身上。 我将与您分享,代码如下:

USE [master]
go


CREATE PROCEDURE [dbo].[sp_radhe] 

AS
BEGIN

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED


-- the current_processes
-- marcelo miorelli 
-- CCHQ 
-- 04 MAR 2013 Wednesday

SELECT es.session_id AS session_id
,COALESCE(es.original_login_name, '') AS login_name
,COALESCE(es.host_name,'') AS hostname
,COALESCE(es.last_request_end_time,es.last_request_start_time) AS last_batch
,es.status
,COALESCE(er.blocking_session_id,0) AS blocked_by
,COALESCE(er.wait_type,'MISCELLANEOUS') AS waittype
,COALESCE(er.wait_time,0) AS waittime
,COALESCE(er.last_wait_type,'MISCELLANEOUS') AS lastwaittype
,COALESCE(er.wait_resource,'') AS waitresource
,coalesce(db_name(er.database_id),'No Info') as dbid
,COALESCE(er.command,'AWAITING COMMAND') AS cmd
,sql_text=st.text
,transaction_isolation =
CASE es.transaction_isolation_level
    WHEN 0 THEN 'Unspecified'
    WHEN 1 THEN 'Read Uncommitted'
    WHEN 2 THEN 'Read Committed'
    WHEN 3 THEN 'Repeatable'
    WHEN 4 THEN 'Serializable'
    WHEN 5 THEN 'Snapshot'
END
,COALESCE(es.cpu_time,0) 
    + COALESCE(er.cpu_time,0) AS cpu
,COALESCE(es.reads,0) 
    + COALESCE(es.writes,0) 
    + COALESCE(er.reads,0) 
+ COALESCE(er.writes,0) AS physical_io
,COALESCE(er.open_transaction_count,-1) AS open_tran
,COALESCE(es.program_name,'') AS program_name
,es.login_time
FROM sys.dm_exec_sessions es
LEFT OUTER JOIN sys.dm_exec_connections ec ON es.session_id = ec.session_id
LEFT OUTER JOIN sys.dm_exec_requests er ON es.session_id = er.session_id
LEFT OUTER JOIN sys.server_principals sp ON es.security_id = sp.sid
LEFT OUTER JOIN sys.dm_os_tasks ota ON es.session_id = ota.session_id
LEFT OUTER JOIN sys.dm_os_threads oth ON ota.worker_address = oth.worker_address
CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) AS st
where es.is_user_process = 1 
  and es.session_id <> @@spid
  and es.status = 'running'
ORDER BY es.session_id

end 

GO
在过去的几年里,这个程序对我来说非常好。 运行它只需键入sp_radhe

关于将sp_radhe放入主数据库

我使用以下代码并将其设为系统存储过程

exec sys.sp_MS_marksystemobject 'sp_radhe'

您可以在下面的链接中看到

Creating Your Own SQL Server System Stored Procedures

关于事务隔离级别

Questions About T-SQL Transaction Isolation Levels You Were Too Shy to Ask

Jonathan Kehayias

  

更改事务隔离级别后,它只会在更改时更改   范围在程序结束时或退货电话退出,或者如果   您可以使用SET TRANSACTION ISOLATION LEVEL再次显式更改它。

     

此外,TRANSACTION ISOLATION LEVEL仅限于   存储过程,因此您可以拥有多个嵌套存储过程   以他们自己特定的隔离级别执行。

答案 3 :(得分:11)

exec sp_lock

此查询应该为您提供现有锁定。

exec sp_who SPID -- will give you some info

有spid,你可以检查活动监视器(进程选项卡)以找出锁定表的进程(&#34;详细信息&#34;有关更多信息和&#34;杀死进程&#34;要杀死它)

答案 4 :(得分:4)

您还可以使用sp_who2来提供更多信息

以下是一些信息http://dbadiaries.com/using-sp_who2-to-help-with-sql-server-troubleshooting

答案 5 :(得分:1)

剧情扭转!

您可以拥有持有排他锁的孤立分布式事务,并且如果脚本假定存在与该事务关联的会话(没有!),则不会看到它们。运行以下脚本以识别这些事务:

;WITH ORPHANED_TRAN AS (
SELECT
    dat.name,
    dat.transaction_uow,
    ddt.database_transaction_begin_time,
    ddt.database_transaction_log_bytes_reserved,
    ddt.database_transaction_log_bytes_used
FROM
    sys.dm_tran_database_transactions ddt,
    sys.dm_tran_active_transactions dat,
    sys.dm_tran_locks dtl
WHERE
    ddt.transaction_id = dat.transaction_id AND
    dat.transaction_id = dtl.request_owner_id AND
    dtl.request_session_id = -2 AND
    dtl.request_mode = 'X'
)
SELECT DISTINCT * FROM ORPHANED_TRAN

一旦确定了事务,请使用transaction_uow列在MSDTC中找到它并决定是中止还是提交它。如果该交易被标记为“可疑”(旁边带有问号),则您可能想中止该交易。

您还可以通过在KILL命令中指定transaction_uow来终止工作单元(UOW):

KILL '<transaction_uow>'

参考文献:

https://docs.microsoft.com/en-us/sql/t-sql/language-elements/kill-transact-sql?view=sql-server-2017#arguments

https://www.mssqltips.com/sqlservertip/4142/how-to-kill-a-blocking-negative-spid-in-sql-server/

答案 6 :(得分:0)

根据官方文档,sp_lock被标记为已弃用:

  

此功能处于维护模式,以后可能会删除   版本的Microsoft SQL Server。避免在新功能中使用此功能   开发工作,并计划修改当前使用的应用程序   此功能。

,建议改用sys.dm_tran_locks。该动态管理对象返回有关当前活动的锁管理器资源的信息。每行表示对锁管理器的当前活动请求,该请求是已授予或正在等待授予的锁。

sp_lock相比,它通常以更用户友好的语法返回更多详细信息。

whoisactive编写的Adam Machanic例程非常适合检查您环境中的当前活动,并查看哪些类型的等待/锁定使查询变慢。您可以很容易地找到阻止查询的内容以及其他大量方便的信息。


例如,假设我们在默认的SQL Server隔离级别-已提交读取中运行以下查询。每个查询都在单独的查询窗口中执行:

-- creating sample data
CREATE TABLE [dbo].[DataSource]
(
    [RowID] INT PRIMARY KEY
   ,[RowValue] VARCHAR(12)
);

INSERT INTO [dbo].[DataSource]([RowID], [RowValue])
VALUES (1,  'samle data');

-- query window 1
BEGIN TRANSACTION;

    UPDATE [dbo].[DataSource]
    SET [RowValue] = 'new data'
    WHERE [RowID] = 1;

--COMMIT TRANSACTION;

-- query window 2
SELECT *
FROM [dbo].[DataSource];

然后执行sp_whoisactive(仅显示部分列):

enter image description here

您可以轻松地看到阻塞SELECT语句的会话,甚至是其T-SQL代码。该例程有很多参数,因此您可以检查docs以获得更多详细信息。

如果我们查询sys.dm_tran_locks视图,我们可以看到一个会话正在等待资源的共享锁,而该资源被其他会话具有排他锁:

enter image description here

答案 7 :(得分:0)

这应该为您提供现有锁的所有详细信息。我从某个地方得到了交叉应用部分,但我忘了它在哪里。如果您碰巧发现了类似的帖子,请编辑此答案并为我添加链接。谢谢。

DECLARE @tblVariable TABLE(SPID INT, Status VARCHAR(200), [Login] VARCHAR(200), HostName VARCHAR(200), 
    BlkBy VARCHAR(200), DBName VARCHAR(200), Command VARCHAR(200), CPUTime INT, 
    DiskIO INT, LastBatch VARCHAR(200), ProgramName VARCHAR(200), _SPID INT, 
    RequestID INT)

INSERT INTO @tblVariable
EXEC Master.dbo.sp_who2

SELECT v.*, t.TEXT 
FROM @tblVariable v
INNER JOIN sys.sysprocesses sp ON sp.spid = v.SPID
CROSS APPLY sys.dm_exec_sql_text(sp.sql_handle) AS t
ORDER BY BlkBy DESC, CPUTime DESC

然后您可以谨慎地杀死阻止您表的SPID。

kill 104 -- Your SPID

答案 8 :(得分:0)

我和一位同事为此创建了一个工具。 它是会话产生的所有锁的直观表示。 试试看(http://www.sqllockfinder.com),它是开源(https://github.com/LucBos/SqlLockFinder