简体   繁体   中英

How can I kill MySQL queries or sleeping connections every 60 seconds in Windows?

I want to check my MySQL server every minute and kill queries that have run longer than 150 seconds. The main reason I want to do this is because I don't want queries from certain people to lock up the DB for everyone else. I know this is not the ultimate solution to the problem, but at least it's a fallback in case something goes wrong with a query. I don't have a slave DB (this is just an at-home project).

I'd like to schedule a script to run that does this for me. I'm unfamiliar with Perl or Ruby and I need it done on my Windows 2008 Server box. I've looked into creating a simple cmd line script, but that doesn't seem to be possible. I know currently I can do something like this but I have to do it manually:

mysqladmin processlist
mysqladmin kill

Anyone have any ideas or examples on how I could do this?

If you have Wscript installed - I think it should be - you can try this. Save as "somethingorother.vbs" and execute every now and then. Or you can use the provided loop. Both loop and kill-for-real options are commented; test the script before uncommenting on a production server.

I assume that 'mysqladmin processlist' outputs something like this (taken from my XP):

+----+------+----------------+----+---------+------+-------+------------------+
| Id | User | Host           | db | Command | Time | State | Info             |
+----+------+----------------+----+---------+------+-------+------------------+
| 21 | root | localhost:1648 |    | Query   | 0    |       | show processlist |
+----+------+----------------+----+---------+------+-------+------------------+

So we have to eliminate rows containing "----" and rows containing "Id | User", and what remains is

| 21 | root | localhost:1648 |    | Query   | 0    |       | show processlist |

which we can split by pipe signs '|', getting nine fields from 0 to 8:

0   1     2          3          4      5        6      7           8
 | 21 | root | localhost:1648 |    | Query   | 0    |       | show processlist |

Field #1 is Id, and field #6 yields the run time.

Option Explicit

Dim objShell, objWshScriptExec, objStdOut, strLine
Dim id, fields, rt, Killer, KillRun

' While True
'     WScript.Sleep 150000

Set objShell = CreateObject("WScript.Shell")
Set objWshScriptExec = objShell.Exec("mysqladmin processlist")
Set objStdOut = objWshScriptExec.StdOut

While Not objStdOut.AtEndOfStream
   strLine = objStdOut.ReadLine
   If (InStr(strLine, "----") = 0 and InStr(strLine, "| Id | User |") = 0) Then
       fields = Split(strLine, "|")
       id = trim(fields(1))
       rt = trim(fields(6))
       If rt > 150 Then
           ' Set Killer = CreateObject("WScript.Shell")
           ' Set KillRun = objShell.Exec("mysqladmin kill " & id)
           echo 
       End If
   End If
Wend

' Wend

Here is the final script I ended up using. Thanks to Iserni with his initial answer that helped me get to this point!

I ended up launching this from a .bat file where csript.exe is call because I can output messages to the command line console (rather than a message box). If you want to output to a text file, you can add that as well, just make sure you launch the .bat file with full Administrator UAC access. Here is what the .bat file contains:

C:\Windows\System32\cscript.exe "C:\Program Files\MySQL\MySQL Server 5.6\bin\kill-slow-queries.vbs"

And here is what is inside of the .vbs file:

    Option Explicit

    Dim objShell, objWshScriptExec, objStdOut, strLine, fields
    Dim id, rt, Killer, KillRun

     While True
         WScript.Sleep 10000

    Set objShell = CreateObject("WScript.Shell")
    Set objWshScriptExec = objShell.Exec("C:\Program Files\MySQL\MySQL Server 5.6\bin\mysqladmin processlist -u root -pMYPASSWORD")
    Set objStdOut = objWshScriptExec.StdOut

On Error Resume Next
    While Not objStdOut.AtEndOfStream
       strLine = objStdOut.ReadLine
       If InStr(strLine, "| 1") > 0 or InStr(strLine, "| 2") > 0 or InStr(strLine, "| 3") > 0 or InStr(strLine, "| 4") > 0 or InStr(strLine, "| 5") > 0 or InStr(strLine, "| 6") > 0 or InStr(strLine, "| 7") > 0 or InStr(strLine, "| 8") > 0  or InStr(strLine, "| 9") > 0 Then
           fields = Split(strLine, "|") 
           id = trim(fields(1))
           rt = trim(fields(6))
           If rt = "" Then 
              rt = 0
           End If
           WScript.Echo "ID: " + id + " Time: " + rt
           If rt > 80 Then
                Set Killer = CreateObject("WScript.Shell")
                Set KillRun = objShell.Exec("C:\Program Files\MySQL\MySQL Server 5.6\bin\mysqladmin kill " + id + " -u root -pMYPASSWORD")
               WScript.Echo "Killed ID: " + id
           End If
       End If

     Wend

      WScript.Echo ""
      WScript.Echo ""

    Wend

The reason I have an If statement that checks for each Integer is because it guarantees and exact match to an ID number of a process. Anything other than those nine options will fail, and you never know what the process list could contain there, so better safe than sorry.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM