Back to all posts

What is Blocking in SQL, How to solve blocking, and Kill Session

What is Blocking in SQL? Blocking occurs in SQL Server when one query or transaction holds a lock on a resource (like a row or table) and prevents other qu…

What is Blocking in SQL?

Blocking occurs in SQL Server when one query or transaction holds a lock on a resource (like a row or table) and prevents other queries or transactions from accessing it. This can slow down or stop other operations until the lock is released.

How to Find Blocking

Use the sp_who2 Command: Run the following command to see all sessions and find blocking:

SQL
EXEC sp_who2;

Look at the BlkBy column to identify blocked sessions. If a session is being blocked, the BlkBy column will show the ID of the blocking session.

Use DBCC OPENTRAN to Find Long-Running Transactions: Run this command to see the oldest open transaction in your database:

Java
  -- DBCC OPENTRAN('YourDatabaseName');
   DBCC OPENTRAN(AdventureWorksDW2022);

This will help identify transactions that are holding locks for a long time.

Check the Blocking Details with Dynamic Management Views (DMVs): Use the following query to get details about the blocking sessions:

SQL
   SELECT 
       blocking_session_id AS BlockingSession, 
       session_id AS BlockedSession,
       wait_type, 
       wait_time / 1000 AS WaitTimeInSeconds, 
       wait_resource 
   FROM sys.dm_exec_requests
   WHERE blocking_session_id <> 0;

This query shows the session ID that is blocking others and provides details about the wait time and resource.

Check details of the blocking transaction:

C++
DBCC INPUTBUFFER(57);

Check details of the Session:

SQL
EXEC sp_who2 57;

How to Solve Blocking

Identify the Blocking Session:

  1. Use sp_who2, DBCC OPENTRAN, or DMVs to find the session_id that is causing the block.
  2. Terminate the Blocking Session if Needed: If the blocking session is not needed or causing issues, use the KILL command to terminate it:
  3. KILL <Session_id>, Replace <session_id> with the ID of the blocking session.

Use NOLOCK Hint to Avoid Blocking Reads:

Use the NOLOCK table hint to perform reads without taking shared locks:

SQL
SELECT * FROM YourTable WITH (NOLOCK);

This shows the query being executed by the blocking session.

By following these steps, you can identify and resolve blocking issues in SQL Server to maintain smooth database operations.

Use usp_FindAndResolveBlocking SP for find and resolve blocking in easy way.

SQL
CREATE PROCEDURE usp_FindAndResolveBlocking
    @DatabaseName SYSNAME,      -- Name of the database to check
    @BlockingSessionId INT = NULL   -- Optional: Session ID to terminate
AS
BEGIN
    SET NOCOUNT ON;

    -- Step 1: Display blocking sessions using sp_who2
   
    EXEC sp_who2;

    -- Step 2: Display the oldest active transaction in the specified database
    DBCC OPENTRAN(@DatabaseName);

	declare @SessionID int = (Select top 1 blocking_session_id from sys.dm_exec_requests WHERE blocking_session_id <> 0)

    -- Step 3: Display blocking details using DMVs
    PRINT 'Displaying details of blocked and blocking sessions:';
    SELECT 
        blocking_session_id AS BlockingSession, 
        session_id AS BlockedSession,
        wait_type, 
        wait_time / 1000 AS WaitTimeInSeconds, 
        wait_resource
    FROM sys.dm_exec_requests
    WHERE blocking_session_id <> 0;

	-- Check details of the Session:
	EXEC sp_who2 @SessionID;

	--Check details of the blocking transaction:

		DBCC INPUTBUFFER(@SessionID);

    -- Step 4: Display the input buffer for a specified blocking session ID
    IF @BlockingSessionId IS NOT NULL
    BEGIN
        PRINT 'Displaying the input buffer for the specified blocking session:';
        DBCC INPUTBUFFER(@BlockingSessionId);
        
        -- Step 5: Terminate the blocking session if specified
        PRINT 'Terminating the blocking session:';
		DECLARE @sqlCmd VARCHAR(MAX)
		SET @sqlCmd = ''
        SELECT   @sqlCmd = @sqlCmd + 'KILL ' + CAST(@SessionID AS VARCHAR)
		EXEC(@sqlCmd)
    END
    ELSE
    BEGIN
        PRINT 'No blocking session ID specified for termination.';
    END
END;
GO

--EXEC usp_FindAndResolveBlocking 'AdventureWorksDW2022'

Blocking Tree code generator

SQL
CREATE PROCEDURE usp_BlockingTree
AS
BEGIN
    SET NOCOUNT ON;

    -- Step 1: Process details with waits
    SELECT 
        R.spid AS SPID,
        R.blocked AS BLOCKED,
        R.waittime / 1000.0 AS WaitTimeSec,         -- Wait time in seconds
        R.lastwaittype AS WaitType,                 -- Type of wait (LCK_M_X etc.)
        R.loginame AS LoginName,                    -- User
        R.hostname AS HostName,                     -- Machine name
        DB_NAME(R.dbid) AS DBName,                  -- Database name
        REPLACE(REPLACE(T.TEXT, CHAR(10), ' '), CHAR(13), ' ') AS BatchText
    INTO #tmpProcess
    FROM sys.sysprocesses R
    CROSS APPLY sys.dm_exec_sql_text(R.sql_handle) T;

    -- Step 2: Recursive CTE for blocking chain
    WITH BlockerTree (SPID, BLOCKED, LEVEL, WaitTimeSec, WaitType, LoginName, HostName, DBName, BatchText)
    AS
    (
        -- Root blockers
        SELECT 
            SPID,
            BLOCKED,
            CAST(RIGHT('0000' + CAST(SPID AS VARCHAR), 4) AS VARCHAR(1000)) AS LEVEL,
            WaitTimeSec,
            WaitType,
            LoginName,
            HostName,
            DBName,
            BatchText
        FROM #tmpProcess R
        WHERE (BLOCKED = 0 OR BLOCKED = SPID)
          AND EXISTS (SELECT 1 FROM #tmpProcess R2 WHERE R2.BLOCKED = R.SPID AND R2.BLOCKED <> R2.SPID)

        UNION ALL

        -- Children (blocked processes)
        SELECT 
            R.SPID,
            R.BLOCKED,
            CAST(BlockerTree.LEVEL + RIGHT('0000' + CAST(R.SPID AS VARCHAR), 4) AS VARCHAR(1000)),
            R.WaitTimeSec,
            R.WaitType,
            R.LoginName,
            R.HostName,
            R.DBName,
            R.BatchText
        FROM #tmpProcess R
        INNER JOIN BlockerTree ON R.BLOCKED = BlockerTree.SPID
        WHERE R.BLOCKED > 0 AND R.BLOCKED <> R.SPID
    )

    -- Step 3: Final output
    SELECT 
        CASE 
            WHEN LEN(LEVEL)/4 - 1 = 0 THEN 'ROOT BLOCKER --> ' 
            ELSE REPLICATE('   ', LEN(LEVEL)/4 - 1) + '|--- ' 
        END
        + CAST(SPID AS NVARCHAR(10)) AS BlockingTree,

        BLOCKED,
        WaitTimeSec,
        WaitType,
        LoginName,
        HostName,
        DBName,
        BatchText
    FROM BlockerTree
    ORDER BY LEVEL;

    DROP TABLE #tmpProcess;
END;
GO

-- Run it
EXEC usp_BlockingTree;
 
SQL
--Kill All sessions

use master
go
 
DECLARE @dbName SYSNAME
DECLARE @sqlCmd VARCHAR(MAX)
 
SET @sqlCmd = ''
SET @dbName = 'dbname' -- Change database name here
 
SELECT   @sqlCmd = @sqlCmd + 'KILL ' + CAST(session_id AS VARCHAR) +
         CHAR(13)
FROM     sys.dm_exec_sessions
WHERE    DB_NAME(database_id) = @dbName
 
PRINT @sqlCmd
 
--EXEC (@sqlCmd)
https://youtu.be/6-z9xU4MdkQ?si=UnnUBmATy1Xi4-Wj
https://youtu.be/3B5bLe0T3qs?si=OAC4MhzYCQqy1Oky

Keep building your data skillset

Explore more SQL, Python, analytics, and engineering tutorials.