Finding long running query and killing it

  • Expert, I am working on scheduling a job which runs every 10 minutes and kill any active session (which is active for more than 10 minutes) from a specific user. I also would like to get an email everytime the session is killed. Can please someone help me with this?

    SET NOCOUNT ON

    -- Table variable to hold InputBuffer data

    DECLARE @Inputbuffer TABLE

    (

    EventType NVARCHAR(30) NULL,

    Parameters INT NULL,

    EventInfo NVARCHAR(4000) NULL

    )

    -- Table variable to hold running processes information

    DECLARE @BusyProcess TABLE

    (

    SPID INT,

    Status VARCHAR(100),

    Login VARCHAR(100),

    HostName VARCHAR(100),

    DBName VARCHAR(100),

    Command VARCHAR(200),

    CPUTime INT,

    DiskIO INT,

    LastBatch DATETIME,

    ProgramName VARCHAR(200),

    EventInfo NVARCHAR(4000), -- extra column to hold actual stored procedure or batch call text

    EventTime INT -- time in minutes, a process is running

    )

    -- Insert all running processes information to table variable

    INSERT @BusyProcess

    ( SPID, Status, Login, HostName, DBName, Command, CPUTime,

    DiskIO, LastBatch, ProgramName )

    SELECT spid,status,loginame,hostname,DB_NAME(dbid),cmd,cpu,physical_io,last_batch,program_name

    FROM SYS.SYSPROCESSES

    WHERE

    1 = CASE WHEN Status IN ( 'RUNNABLE', 'SUSPENDED' ) THEN 1

    --Transactions that are open not yet committed or rolledback

    WHEN Status = 'SLEEPING' AND open_tran > 0 THEN 1

    ELSE 0 END

    AND cmd NOT LIKE 'BACKUP%'

    AND hostname in ('hostname')

    -- Cursor to add actuall Procedure or Batch statement for each process

    DECLARE cur_BusyProcess Cursor

    FOR SELECT SPID

    FROM @BusyProcess

    OPEN cur_BusyProcess

    DECLARE @SPID INT

    Fetch NEXT FROM cur_BusyProcess INTO @SPID

    While ( @@FETCH_STATUS <> -1 )

    BEGIN

    INSERT @Inputbuffer

    EXEC ( 'DBCC INPUTBUFFER(' + @SPID + ')'

    )

    UPDATE @BusyProcess

    SET EventInfo = I.EventInfo,

    EventTime = DATEDIFF(MI,LastBatch,GETDATE())

    FROM @BusyProcess b

    CROSS JOIN @Inputbuffer i

    WHERE B.SPID = @SPID

    DELETE FROM @Inputbuffer

    FETCH NEXT FROM cur_BusyProcess INTO @SPID

    END

    CLOSE cur_BusyProcess

    DEALLOCATE cur_BusyProcess

  • Can please someone help me with this?

    With what, exactly?

    We're busy people and we're not paid to answer questions here, so ...

    Please be more specific, rather than asking people to examine every single line of code which you have posted in the hope of determining what you're asking for.

    The absence of evidence is not evidence of absence
    - Martin Rees
    The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
    - Phil Parkin

  • Thanks Phil but this question is for people who are not that busy so they can take their time and look at the code? If my question isn't clear then please tell me? Again, this statement is not for busy people.

  • What do you need help with? What's the code doing or not doing that it shouldn't?

    And I will reiterate my comment from last time this came up

    GilaMonster (6/10/2016)


    Chitown (6/9/2016)


    I just can't seem to educate users who runs this long query. Even though they pull unnecessary data, they just don't seem to understand. This is my last resort

    Thing is, if you do this, the users have 'proof' that you're hindering their ability to do their job. They take that to your boss and suddenly you're the bad guy.

    This is not a technical problem, don't try to solve it with technology. It's a management and person problem.

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass
  • I'm not sure if this approach would be flexible enough for your needs, but it would leverage some built in features of SQL Server, rather than attempting to code your own.

    There is an interesting setting, called 'query governor cost limit', which can be configured at the server level or set at the session level, that enforces an upper limit on user queries (not system sessions) that would exceed an estimated number of "seconds". Rather than killing sessions, what it does is cancel the query execution before it starts and instead returns an error 8649.

    NOTE: Keep in mind that the limit value is not actual seconds but some relative value that would need to experiment with. Also, it probably relies on table and index statistics for accurate estimates, so maintaining stats would be important.

    Here is an example what it would look like when implemented as a session level setting:

    SET QUERY_GOVERNOR_COST_LIMIT 10;

    SELECT .. FROM ..

    JOIN .. JOIN .. JOIN ..

    <some complicated query>

    Msg 8649, Level 17, State 1, Line 3

    The query has been canceled because the estimated cost of this query (50805) exceeds the configured threshold of 10. Contact the system administrator.

    This error message would be raised back to the user, and also you can simply setup an operational Alert with email notification on this specific error number.

    "Do not seek to follow in the footsteps of the wise. Instead, seek what they sought." - Matsuo Basho

  • Chitown (9/8/2016)


    --If my question isn't clear then please tell me?--

    Seriously? Your question was this

    Can please someone help me with this?

    That's a clear question, I'll agree. Possible answers that come to mind:

    Yes, No, Maybe

    The question that I suspected you meant to ask:

    Here is a long piece of code which I have written. What I am trying to do with the code is find long-running queries and kill them. Please read through all of my code, understand it and identify any problematic areas. Then suggest changes to all parts of the code which require them, such that I can satisfy my requirement.

    The absence of evidence is not evidence of absence
    - Martin Rees
    The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
    - Phil Parkin

  • If this is SQL Server 2012 or better (that's the forum you're posting in), why are you using sys.processes and DBCC INPUT BUFFER instead of the Dynamic Management Views (DMV) like sys.dm_exec_requests and sys.dm_exec_sql_text, which are going to be a heck of a lot easier to manage than what you have. You can get the query text in a single query instead of running it through a cursor as you're doing now. That's highly inefficient. If you need help building that query, I can recommend the book Performance Tuning With Dynamic Management Views (it's free to download). That will be a much better way to do this same thing.

    Now, as to whether or not you should automatically kill long running queries, that's another question. If the query is long running and it has modified data, your rollback could be longer than the query was. You're going to need to be very cautious with this approach. It could cause more problems than it solves.

    "The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
    - Theodore Roosevelt

    Author of:
    SQL Server Execution Plans
    SQL Server Query Performance Tuning

  • Chitown (9/8/2016)


    Expert, I am working on scheduling a job which runs every 10 minutes and kill any active session (which is active for more than 10 minutes) from a specific user. I also would like to get an email everytime the session is killed. Can please someone help me with this?...

    Please don't do this. Read Gail's comments very carefully and understand what she is trying to tell you. Speak to management.

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • Chitown (9/8/2016)


    Expert, I am working on scheduling a job which runs every 10 minutes and kill any active session (which is active for more than 10 minutes) from a specific user. I also would like to get an email everytime the session is killed. Can please someone help me with this?

    SET NOCOUNT ON

    -- Table variable to hold InputBuffer data

    DECLARE @Inputbuffer TABLE

    (

    EventType NVARCHAR(30) NULL,

    Parameters INT NULL,

    EventInfo NVARCHAR(4000) NULL

    )

    -- Table variable to hold running processes information

    DECLARE @BusyProcess TABLE

    (

    SPID INT,

    Status VARCHAR(100),

    Login VARCHAR(100),

    HostName VARCHAR(100),

    DBName VARCHAR(100),

    Command VARCHAR(200),

    CPUTime INT,

    DiskIO INT,

    LastBatch DATETIME,

    ProgramName VARCHAR(200),

    EventInfo NVARCHAR(4000), -- extra column to hold actual stored procedure or batch call text

    EventTime INT -- time in minutes, a process is running

    )

    -- Insert all running processes information to table variable

    INSERT @BusyProcess

    ( SPID, Status, Login, HostName, DBName, Command, CPUTime,

    DiskIO, LastBatch, ProgramName )

    SELECT spid,status,loginame,hostname,DB_NAME(dbid),cmd,cpu,physical_io,last_batch,program_name

    FROM SYS.SYSPROCESSES

    WHERE

    1 = CASE WHEN Status IN ( 'RUNNABLE', 'SUSPENDED' ) THEN 1

    --Transactions that are open not yet committed or rolledback

    WHEN Status = 'SLEEPING' AND open_tran > 0 THEN 1

    ELSE 0 END

    AND cmd NOT LIKE 'BACKUP%'

    AND hostname in ('hostname')

    -- Cursor to add actuall Procedure or Batch statement for each process

    DECLARE cur_BusyProcess Cursor

    FOR SELECT SPID

    FROM @BusyProcess

    OPEN cur_BusyProcess

    DECLARE @SPID INT

    Fetch NEXT FROM cur_BusyProcess INTO @SPID

    While ( @@FETCH_STATUS <> -1 )

    BEGIN

    INSERT @Inputbuffer

    EXEC ( 'DBCC INPUTBUFFER(' + @SPID + ')'

    )

    UPDATE @BusyProcess

    SET EventInfo = I.EventInfo,

    EventTime = DATEDIFF(MI,LastBatch,GETDATE())

    FROM @BusyProcess b

    CROSS JOIN @Inputbuffer i

    WHERE B.SPID = @SPID

    DELETE FROM @Inputbuffer

    FETCH NEXT FROM cur_BusyProcess INTO @SPID

    END

    CLOSE cur_BusyProcess

    DEALLOCATE cur_BusyProcess

    I do apologize, I didn't realize that I had asked the related question before. Anyways, this is the query I have. I am executing this SP but it is still not killing the session. Hostname is ITN, which is mine and I am testing this code in a lower environment. I have open transaction which I was running for over 1 minute and then I executed this SP but it didn't kill the session.

    ALTER proc [dbo].[check_longrunningQueries] @Total_time_Executed int

    as

    BEGIN

    SET NOCOUNT ON --added to prevent extra result sets from

    -- interfering with SELECT statements.

    --dbo.check_GatewayOracle_longrunningQueries 60

    SET NOCOUNT ON

    Declare @spid int,

    @loginname Varchar(50),

    @programname Varchar(50),

    @host Varchar(50),

    @startime datetime,

    @lastudpatetime datetime ,

    @DBName Varchar(50),

    @query Varchar(4000) ,

    @msg Varchar(8000) ,

    @kill varchar(50) --<<EZ

    DECLARE db_cursor CURSOR FOR

    SELECT spid, loginame, program_name, hostname as "From host", login_time, last_batch, DB_NAME(dbid) AS "Against database" ,

    (SELECT text FROM sys.dm_exec_sql_text(sql_handle))as "Query executed"

    FROM master..sysprocesses WHERE hostname= 'ITN' and open_tran > 0 and DATEDIFF (minute, last_batch, GETDATE()) > @Total_time_Executed

    OPEN db_cursor

    set @msg = 'Alert:A long running transactions were killed'

    set @Total_time_Executed = 1

    FETCH NEXT FROM db_cursor INTO @spid, @loginname , @programname , @host , @startime , @lastudpatetime , @DBName , @query

    WHILE @@FETCH_STATUS = 0

    BEGIN

    set @kill = 'Kill ' + cast( @spid as varchar(5))

    exec(@kill)

    EXEC msdb.dbo.sp_send_dbmail

    @profile_name = 'Default Mail Profile',

    @recipients = 'email address',

    @body = @query,

    @subject = 'The long running transactions from were killed '

    FETCH NEXT FROM db_cursor INTO @spid, @loginname , @programname , @host , @startime , @lastudpatetime , @DBName , @query

    END

    CLOSE db_cursor

    DEALLOCATE db_cursor

    END

  • I agree with Chris and Gail.

    Every one of those emails are going to result in a "WHY DID THEY KILL MY JOB?" scream.

    __________________________________________________

    Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
    Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills

  • Guys I do appreciate you telling me that this is not a good practice and I do agree but this is what I was asked to do. And before we implement any changes in the prod environment, CAB has to approve the change. So basically we want users to scream if they run any adhoc query which they r not supposed to run.

  • The Dixie Flatline (9/8/2016)


    I agree with Chris and Gail.

    Every one of those emails are going to result in a "WHY DID THEY KILL MY JOB?" scream.

    That's why it's important to limit execution of these queries via a query cost theshold and for the DBA to get sign-off from executive management. That way the DBA doesn't have to answer the question "Why did you kill my query?"; instead the user has to answer for why they are attempting to run complicated ad-hoc queries that exceed X seconds/minutes in the first place. It's conceptually no differant than using permissions to restrict what objects the users have access to.

    I'm offering advice under the assumption that this is a mission critical transactional database, some users are allowed to run ad-hoc queries, but there are occasional long running queries that cause performance issues or blocking. If the real problem is that users shouldn't be running ad-hoc queries in the first place, then the solution would be to tighten up on access using role based authorization and permissions.

    "Do not seek to follow in the footsteps of the wise. Instead, seek what they sought." - Matsuo Basho

  • What I'd suggest is, instead of killing sessions, and instead of using the Query Govenor (users aren't going to voluntarily set that, and server-wide means *everything* gets it), is to set up resource govenor groups, put maintenance and normal app stuff into one and have user ad-hoc queries fall into another, and set restrictions and limits on the ad-hoc query pool.

    Gail Shaw
    Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
    SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

    We walk in the dark places no others will enter
    We stand on the bridge and no one may pass

Viewing 13 posts - 1 through 12 (of 12 total)

You must be logged in to reply to this topic. Login to reply