【问题标题】:How to check which locks are held on a table如何检查表上持有哪些锁
【发布时间】:2010-10-16 05:26:11
【问题描述】:

我们如何检查查询批次对哪些行应用了哪些数据库锁?

任何工具可以实时突出表行级锁定?

数据库:SQL Server 2005

【问题讨论】:

    标签: sql sql-server database performance sql-server-2005


    【解决方案1】:

    您可以通过运行以下命令找到阻塞 sql 和等待 sql:

    SELECT
        t1.resource_type ,
        DB_NAME( resource_database_id) AS dat_name ,
        t1.resource_associated_entity_id,
        t1.request_mode,
        t1.request_session_id,
        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 wait_sql,
        t2.blocking_session_id,
        ( SELECT TEXT FROM sys.sysprocesses p CROSS apply sys.dm_exec_sql_text ( p.sql_handle ) WHERE p.spid = t2.blocking_session_id ) AS blocking_sql 
    FROM
        sys.dm_tran_locks t1,
        sys.dm_os_waiting_tasks t2 
    WHERE
        t1.lock_owner_address = t2.resource_address
    

    【讨论】:

      【解决方案2】:

      您可以通过以下脚本找到详细信息。

      -- List all Locks of the Current Database 
      SELECT TL.resource_type AS ResType 
            ,TL.resource_description AS ResDescr 
            ,TL.request_mode AS ReqMode 
            ,TL.request_type AS ReqType 
            ,TL.request_status AS ReqStatus 
            ,TL.request_owner_type AS ReqOwnerType 
            ,TAT.[name] AS TransName 
            ,TAT.transaction_begin_time AS TransBegin 
            ,DATEDIFF(ss, TAT.transaction_begin_time, GETDATE()) AS TransDura 
            ,ES.session_id AS S_Id 
            ,ES.login_name AS LoginName 
            ,COALESCE(OBJ.name, PAROBJ.name) AS ObjectName 
            ,PARIDX.name AS IndexName 
            ,ES.host_name AS HostName 
            ,ES.program_name AS ProgramName 
      FROM sys.dm_tran_locks AS TL 
           INNER JOIN sys.dm_exec_sessions AS ES 
               ON TL.request_session_id = ES.session_id 
           LEFT JOIN sys.dm_tran_active_transactions AS TAT 
               ON TL.request_owner_id = TAT.transaction_id 
                  AND TL.request_owner_type = 'TRANSACTION' 
           LEFT JOIN sys.objects AS OBJ 
               ON TL.resource_associated_entity_id = OBJ.object_id 
                  AND TL.resource_type = 'OBJECT' 
           LEFT JOIN sys.partitions AS PAR 
               ON TL.resource_associated_entity_id = PAR.hobt_id 
                  AND TL.resource_type IN ('PAGE', 'KEY', 'RID', 'HOBT') 
           LEFT JOIN sys.objects AS PAROBJ 
               ON PAR.object_id = PAROBJ.object_id 
           LEFT JOIN sys.indexes AS PARIDX 
               ON PAR.object_id = PARIDX.object_id 
                  AND PAR.index_id = PARIDX.index_id 
      WHERE TL.resource_database_id  = DB_ID() 
            AND ES.session_id <> @@Spid -- Exclude "my" session 
            -- optional filter  
            AND TL.request_mode <> 'S' -- Exclude simple shared locks 
      ORDER BY TL.resource_type 
              ,TL.request_mode 
              ,TL.request_type 
              ,TL.request_status 
              ,ObjectName 
              ,ES.login_name;
      
      
      
      --TSQL commands
      SELECT 
             db_name(rsc_dbid) AS 'DATABASE_NAME',
             case rsc_type when 1 then 'null'
                                   when 2 then 'DATABASE' 
                                   WHEN 3 THEN 'FILE'
                                   WHEN 4 THEN 'INDEX'
                                   WHEN 5 THEN 'TABLE'
                                   WHEN 6 THEN 'PAGE'
                                   WHEN 7 THEN 'KEY'
                                   WHEN 8 THEN 'EXTEND'
                                   WHEN 9 THEN 'RID ( ROW ID)'
                                   WHEN 10 THEN 'APPLICATION' end  AS 'REQUEST_TYPE',
      
             CASE req_ownertype WHEN 1 THEN 'TRANSACTION'
                                           WHEN 2 THEN 'CURSOR'
                                           WHEN 3 THEN 'SESSION'
                                           WHEN 4 THEN 'ExSESSION' END AS 'REQUEST_OWNERTYPE',
      
             OBJECT_NAME(rsc_objid ,rsc_dbid) AS 'OBJECT_NAME', 
             PROCESS.HOSTNAME , 
             PROCESS.program_name , 
             PROCESS.nt_domain , 
             PROCESS.nt_username , 
             PROCESS.program_name ,
             SQLTEXT.text 
      FROM sys.syslockinfo LOCK JOIN 
           sys.sysprocesses PROCESS
        ON LOCK.req_spid = PROCESS.spid
      CROSS APPLY sys.dm_exec_sql_text(PROCESS.SQL_HANDLE) SQLTEXT
      where 1=1
      and db_name(rsc_dbid) = db_name()
      
      
      
      --Lock on a specific object
      SELECT * 
      FROM sys.dm_tran_locks
      WHERE resource_database_id = DB_ID()
      AND resource_associated_entity_id = object_id('Specific Table');
      

      【讨论】:

        【解决方案3】:

        我使用动态管理视图 (DMV) 来捕获锁以及被锁定项目的 object_id 或 partition_id。

        (必须切换到要观察的数据库才能获取 object_id)

        SELECT 
             TL.resource_type,
             TL.resource_database_id,
             TL.resource_associated_entity_id,
             TL.request_mode,
             TL.request_session_id,
             WT.blocking_session_id,
             O.name AS [object name],
             O.type_desc AS [object descr],
             P.partition_id AS [partition id],
             P.rows AS [partition/page rows],
             AU.type_desc AS [index descr],
             AU.container_id AS [index/page container_id]
        FROM sys.dm_tran_locks AS TL
        INNER JOIN sys.dm_os_waiting_tasks AS WT 
         ON TL.lock_owner_address = WT.resource_address
        LEFT OUTER JOIN sys.objects AS O 
         ON O.object_id = TL.resource_associated_entity_id
        LEFT OUTER JOIN sys.partitions AS P 
         ON P.hobt_id = TL.resource_associated_entity_id
        LEFT OUTER JOIN sys.allocation_units AS AU 
         ON AU.allocation_unit_id = TL.resource_associated_entity_id;
        

        【讨论】:

        • 我正在尝试使用此语句来找出进程正在等待的对象。我可以清楚地看到一个会话正在等待另一个使用sp_who2sys.dm_os_waiting_task(都试图更新同一个表)。但是您的语句不返回任何行。有什么想法吗?
        【解决方案4】:

        您可以通过以下查询找到当前表上的锁

        USE yourdatabase;
        GO
        
        SELECT * FROM sys.dm_tran_locks
          WHERE resource_database_id = DB_ID()
          AND resource_associated_entity_id = OBJECT_ID(N'dbo.yourtablename');
        

        sys.dm_tran_locks

        如果存在相同request_owner_type的多个实例,则使用request_owner_id列来区分每个实例。对于分布式事务,request_owner_typerequest_owner_guid 列将显示不同的实体信息。

        例如,会话 S1 拥有 Table1 上的共享锁;在会话 S1 下运行的事务 T1 也拥有 Table1 上的共享锁。在这种情况下,sys.dm_tran_locks 返回的 resource_description 列将显示同一资源的两个实例。 request_owner_type 列将一个实例显示为会话,另一个实例显示为事务。此外,resource_owner_id 列将具有不同的值。

        【讨论】:

        • 这显示了进程中不可见的锁!!
        【解决方案5】:

        这并不能准确地向您显示哪些行被锁定,但这可能对您有所帮助。

        您可以通过运行以下命令检查哪些语句被阻止:

        select cmd,* from sys.sysprocesses
        where blocked > 0
        

        它还会告诉您每个块正在等待什么。所以你可以一直追踪,看看哪个语句导致了第一个块,然后导致了其他块。

        编辑添加来自@MikeBlandford的评论:

        blocked 列表示阻塞进程的 spid。你可以运行 kill {spid} 来修复它。

        【讨论】:

        • 阻塞列表示阻塞进程的spid。你可以运行 kill {spid} 来修复它。
        • 如果您不是 DBA 并且无权访问“master”,这是一个很好的脚本。
        【解决方案6】:

        要添加到其他响应,sp_lock 也可用于转储所有正在运行的进程的完整锁定信息。输出可能是压倒性的,但如果您想确切地知道锁定了什么,运行它是很有价值的。我通常将它与sp_who2 一起使用,以快速解决锁定问题。

        有多种不同版本的“更友好”sp_lock 过程在线可用,具体取决于相关 SQL Server 的版本。

        在您的情况下,对于 SQL Server 2005,sp_lock 仍然可用,但已弃用,因此现在建议对此类事情使用 sys.dm_tran_locks 视图。您可以找到一个如何“滚动自己”的 sp_lock 函数 here 的示例。

        【讨论】:

          【解决方案7】:

          您还可以使用内置的sp_who2 存储过程来获取 SQL Server 实例上的当前阻塞和阻塞进程。通常,您会在 SQL Profiler 实例旁边运行它以查找阻塞进程并查看 spid 在 profiler 中发出的最新命令。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-12-16
            • 1970-01-01
            • 2016-05-08
            • 2015-04-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多