常被误解的一种SQL Server阻塞场景原创
金蝶云社区-墨迹
墨迹
56人赞赏了该文章 292次浏览 未经作者许可,禁止转载编辑于2024年04月15日 09:25:47

    抓到阻塞信息时,经常会碰到下面的内容,阻塞会话执行的select,怎么可能会阻塞update,不是同时执行(修改,删除或者插入)操作时,由于排他锁才会引发锁争用么?              

1

    我们做个简单的测试,就清楚了

    • 新建会话90执行的SQL,按123的方式逐条执行,不提交事务

            

2

    • 然后新建会话128执行的SQL,按12的方式逐条执行,然后我们会发现128会话显示“正在执行”

            

3

    • 此时使用获取阻塞的SQL,将得到图1的结果

            SELECT t1.resource_type AS [锁类型], DB_NAME(resource_database_id) AS [数据库名],

            t1.resource_associated_entity_id AS [阻塞资源对象],

            t1.resource_description as [资源描述信息], t1.request_mode AS [请求的锁],

            t1.request_session_id AS [等待会话], t2.wait_duration_ms AS [等待时间],      

            (SELECT [text] FROM sys.dm_exec_requests AS r WITH (NOLOCK)                      

                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,

                    (CASE WHEN r.statement_end_offset = -1

                    THEN LEN(CONVERT(nvarchar(max), qt.[text])) * 2

                    ELSE r.statement_end_offset END )/2)

                FROM sys.dm_exec_requests AS r WITH (NOLOCK)

                CROSS APPLY sys.dm_exec_sql_text(r.[sql_handle]) AS qt

                WHERE r.session_id = t1.request_session_id

            ) AS [等待会话执行的SQL],                    

            t2.blocking_session_id AS [阻塞会话],                                        

            (SELECT [text] FROM sys.sysprocesses AS p                                      

                CROSS APPLY sys.dm_exec_sql_text(p.[sql_handle])

                WHERE p.spid = t2.blocking_session_id

            ) AS [阻塞会话执行的批SQL]

            FROM sys.dm_tran_locks AS t1 WITH (NOLOCK)

            INNER JOIN sys.dm_os_waiting_tasks AS t2 WITH (NOLOCK)

            ON t1.lock_owner_address = t2.resource_address OPTION (RECOMPILE);

    到这,问题就很明白了,虽然会话90当前正在执行select * from test1操作,但其之前执行了对testupdate操作,由于事务没有结束,所以锁没有释放,这样当会话128执行update时,由于需要的锁没有释放从而导致阻塞。

    所以,当碰到这类场景的时候,如果阻塞源是select的语句时,需要检查代码,找到阻塞会话之前执行等待会话中更新修改或者删除表的操作来确认原因

    如果阻塞的时间长,需要检查update操作后,是否有长时间执行的SQL,或者代码中有太多的的逻辑,需要耗费时间过长,从而导致整个事务太长。

赞 56