Home » Mysql » How can I stop a MySQL query if it takes too long?

How can I stop a MySQL query if it takes too long?

Posted by: admin November 1, 2017 Leave a comment

Questions:

Is it possible to timeout a query in MySQL?

That is, if any query exceeds the time I specify, it will be killed by MySQL and it will return an error instead of waiting for eternity.

Answers:

There is a nice Perl script on CPAN to do just this:
http://search.cpan.org/~rsoliv/mysql-genocide-0.03/mysql-genocide

One only needs to schedule it to run with the proper parameters. Create a CRONtab file /etc/cron.d/mysql_query_timeout to schedule it to run every minute:

* * * * * root /path/to/mysql-genocide -t 7200 -s -K

Where 7200 is the maxiumum allowed execution time in seconds. The -s switch filters out all except SELECT queries. The -K switch instructs the script to kill the matching processes.

The root user should be able to run local mysql tools without authentication otherwise you will need to provide credentials on the command line.

Questions:
Answers:

I just set up the following bash script as a cron job to accomplish this with MySQL 5.0 (kills any query that has been executing for more than 30 seconds). Sharing it here in case it proves useful to anyone (apologies if my bash scripting style is inefficient or atrocious, it is not my primary development language):

#!/bin/bash
linecount=0
processes=$(echo "show processlist" | mysql -uroot -ppassword)
oldIfs=$IFS
IFS='
'
echo "Checking for slow MySQL queries..."
for line in $processes
do
    if [ "$linecount" -gt 0 ]
        then
            pid=$(echo "$line" | cut -f1)
            length=$(echo "$line" | cut -f6)
            query=$(echo "$line" | cut -f8)
            #Id User    Host    db  Command Time    State   Info
            if [ "$length" -gt 30 ]
                then
                    #echo "$pid = $length"
                    echo "WARNING:  Killing query with pid=$pid with total execution time of $length seconds! (query=$query)"
                    killoutput=$(echo "kill query $pid" | mysql -uroot -ppassword)
                    echo "Result of killing $pid:  $killoutput"
            fi
    fi
    linecount=`expr $linecount + 1`
done
IFS=$oldIfs

Questions:
Answers:

Starting with MySQL 5.1 you can create a stored procedure to query the information_schmea.PROCESSLIST table for all queries that match your criteria for “long running” then iterate over a cursor to kill them. Then setup that procedure to execute on a recurring basis in the event scheduler.

See: http://forge.mysql.com/tools/tool.php?id=106

Questions:
Answers:

I thought it has been around a little longer, but according to this,

MySQL 5.7.4 introduces the ability to set server side execution time limits, specified in milliseconds, for top level read-only SELECT statements.

SELECT 
MAX_STATEMENT_TIME = 1000 --in milliseconds
* 
FROM table;

Note that this only works for read-only SELECT statements.

Questions:
Answers:

The MySQL forum has some threads about this.

This post details how to set up timeouts on the server using innodb_lock_wait_timeout.

Here’s a way to do it programmatically, assuming you’re using JDBC.

Questions:
Answers:

I don’t think the egrep above would find “2000”.
Why not try just selecting the id as well, and avoiding all of that posh shell stuff:

mysql -e 'select id from information_schema.processlist where info is not null and time > 30;'

Questions:
Answers:

Here is my script :

mysql -e 'show processlist\G' |\
egrep -b5 'Time: [6-9]{3,10}' |\
grep 'Id:' |\
cut -d':' -f2 |\
grep -v '155' |\ ## Binary Log PID
sed 's/^ //' |\
while read id
do
    mysql -e "kill $id;"
done

Questions:
Answers:

Since MySQL 5.7.8 there is max_execution_time option that defines the execution timeout for SELECT statements.

Questions:
Answers:

I think this old question needs an updated answer.

You can set a GLOBAL timeout for all your read-only SELECT queries like this:

SET GLOBAL MAX_EXECUTION_TIME=1000;

The time specified is in milliseconds.

If you want the timeout only for a specific query, you can set it inline like this:

SELECT /*+ MAX_EXECUTION_TIME(1000) */ my_column FROM my_table WHERE ...

MySQL returns an error instead of waiting for eternity.

Note that this method only works for read-only SELECTs. If a SELECT statement is determined not to be read-only, then any timer set for it is cancelled and the following NOTE message is reported to the user:

Note 1908 Select is not a read only statement, disabling timer

For statements with subqueries, it limits the top SELECT only. It does not apply to SELECT statements within stored programs. Using the MAX_EXECUTION_TIME hint in SELECT statements within a stored program will be ignored.

Questions:
Answers:

To kill queries based on their thread_id try the query and kill them manually,

SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = ‘Query’ AND TIME > 10;

An alternative and interactive approach would be to output the values to a file using the query,

SELECT CONCAT('KILL ',ID,';')
FROM   INFORMATION_SCHEMA.PROCESSLIST
WHERE  USER = ‘new’
   AND COMMAND = 'Query'
   AND TIME > 10
  INTO   OUTFILE '/tmp/thread_kill.txt';

and then kill the threads in the file using,

 \. /tmp/thread_kill.txt

Another alternative is to look for monitoring tools like MONyog, MySQL Enterprise Monitor, Percona toolkit where you can let the tool to look for the longer/slow queries, locking queries and kill them. With MONyog the added advantage is the slow queries can not just be killed but also inform the user by email regarding which query held up the resources and made the server slow-down.