6

I've recently inherited a MSSQL database as our DBA has moved on to greener pastures. I'm not a DBA and have limited to moderate SQL knowledge but have had to absorb some of his duties and have an issue I am having some trouble navigating around.

We have had an issue where users who access the database via Excel have a tendency to grind database operations to a halt and it impacts our ERP software. Our current method of resolution is to look at the activity monitor in SSMS and kill the offending Microsoft Office application.

I'd like to have a scripted task that runs every few minutes to keep things moving and not have users flock to IT when the system goes down.

I've found that the following query will allow me to pull the lock type and other useful data such as wait time but not the specific application found in the activity monitor.

select * from sys.dm_exec_requests where wait_type = 'LCK_M_S'

Ideally, this code would find the application Microsoft Office with the wait_type of LCK_M_S and kill the longest waiting task and repeat as needed throughout the day.

Thank you in advance for your responses.

3 Answers3

6

You can look at

select session_id, program_name, host_name
from sys.dm_exec_sessions

But those program names can be chosen by the client, so there's no guarantee that you can identify the Excel sessions.

A better solution would be to see if your ERP software supports READ COMMITTED SNAPSHOT isolation, and set the database option that would prevent your Excel users from needing Shared Locks to run queries.

David Browne - Microsoft
  • 49,000
  • 3
  • 53
  • 102
0

You might want to have a look at the Sysinternals tools. They contain a tool called PSKILL.EXE.

This tool will allow you to combine things to partly automate the process of killing processes on the host.

Base Script

The following small script list all processes currently running on a SQL Server instance:

SELECT  sdes.login_time, 
        sdes.[host_name], 
        sdes.host_process_id, 
        sdes.login_name, 
        sdes.nt_domain, 
        sdes.nt_user_name, 
        sdec.client_net_address, 
        sder.wait_type
FROM sys.dm_exec_connections AS sdec 
    JOIN sys.dm_exec_sessions AS sdes 
        ON sdes.session_id = sdec.session_id 
    JOIN sys.dm_exec_requests AS sder 
        ON sder.sql_handle = sdec.most_recent_sql_handle;

This will provide you with an overview of the running tasks.

Combining Script and PsKill.exe

Now if you were to store the PSKILL.exe from the Sysinternals tools in a directory (e.g. D:\Tools\pskill.exe) on your SQL Server, then you could create a script like the following:

SELECT '!! D:\Tools\pskill.exe \\' + sdes.[host_name] + '-u DOMAIN\Administrator -p ThePassWord ' + CAST(sdes.host_process_id AS VARCHAR(10)) + '' AS RemoteKillCommand,  
    sdes.login_time, 
    sdes.[host_name], 
    sdes.host_process_id, 
    sdes.login_name, 
    sdes.nt_domain, 
    sdes.nt_user_name, 
    sdec.client_net_address, 
    sder.wait_type 
FROM sys.dm_exec_connections AS sdec 
    JOIN sys.dm_exec_sessions AS sdes 
        ON sdes.session_id = sdec.session_id 
    JOIN sys.dm_exec_requests AS sder 
    ON sder.sql_handle = sdec.most_recent_sql_handle
    AND sder.wait_type = 'LCK_M_S';

This would create a result set containing the command to remotely kill the session on a remote computer.

Example Results:

+--------------------------------------------------------------------------------+-------------------------+-----------+-----------------+------------+-----------+--------------+--------------------+-----------+
|                               RemoteKillCommand                                |       login_time        | host_name | host_process_id | login_name | nt_domain | nt_user_name | client_net_address | wait_type |
+------------------------------------------------------------------------------------+-------------------------+-----------+-----------------+------------+-----------+--------------+--------------------+-----------+
| !! D:\Tools\pskill.exe \\Computer -u DOMAIN\Administrator -p ThePassWord 23252 | 2022-08-22 15:07:02.330 | Computer  |           23252 | sa         | NULL      | NULL         |     161.78.198.100 | LCK_M_S  |
+--------------------------------------------------------------------------------+-------------------------+-----------+-----------------+------------+-----------+--------------+--------------------+-----------+

Execute RemoteKillCommand in SQLCMD Mode

You can then grab that command form the result set and execute it in a SQL Server Query Window in SQLCMD Mode (can be found under Query | SQLCMD Mode when the focus is in a query window):

!! D:\Tools\pskill \\COMPUTER -u DOMAIN\Administrator -p ThePassWord 23252

This will kill the process 23252 on the remote Computer COMPUTER using the credentials DOMAIN\Administrator and the password ThePassWord.

Of course you would require a Domain Account with sufficient permissions to remotely kill processes on a client's computer!

CAUTION
Process IDs on a client's computer can change quickly. So be sure to run the commands as quick as possible or insert a PSLIST using a similar concatenation to verify that the process is still valid on the client.

Reference Reading

Next Step

The next step would be to automatically execute the generated statement without the !! exclamation marks as a DOS Command using xp_cmdshell. I'll leave that for you to find out...

John K. N.
  • 18,854
  • 14
  • 56
  • 117
-2

If you can find the session id of the user causing the issue you want, then you can kill their session (though not a particular transaction)

KILL 0

https://learn.microsoft.com/en-us/sql/t-sql/language-elements/kill-transact-sql?view=sql-server-ver16

There's another question here which may help your search for the sessions to stop, the suggestion appears to be for using DBCC, but that seems less automatable.

DBCC opentran()

https://stackoverflow.com/questions/6833867/close-kill-transaction

If you have control over what the Excel sheets are running, they are read only, and it doesn't matter if the values are a little wrong. You can add this to the top of the queries, and they won't block other users

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED