acheruns
acheruns

Reputation: 681

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

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.

Upvotes: 47

Views: 69983

Answers (10)

EsmaeelE
EsmaeelE

Reputation: 2668

Using internal feature of mysql/mariadb database to kill long running process may cause harmful termination of vital processes in database.

So we need a safer approach to do this task.

Query on process list table to find long running processes.

Something like below query may be better approach to kill a process not blindly.

SELECT GROUP_CONCAT(CONCAT("KILL ", id) SEPARATOR ';\n')  from information_schema.PROCESSLIST where command='Sleep' AND time > 20000 AND user='user_processor';

Above query show process id (ID) in a group.

So Running it does not do anything but show group of process which candida to be killed.

After doing manual investigation on them you can run appropriate command to kill a specific process.

KILL 1234

Hints:

  1. I separate writer user under the name of user_processor. We tightens search area to specific user.

  2. I grab skeleton of my answer from another stack exchange thread but for now I cant find it to link.

  3. In Mariadb Times column is in seconds. So 20,000 seconds is about 5.5 Hours.


Another way to doing kill task is to use a Graphical Interface to Database engine.

For peoples prefer to do these task visually I suggest using vscode database client Or dbeaver

Upvotes: 0

Westy92
Westy92

Reputation: 21295

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_EXECUTION_TIME = 1000 --in milliseconds
* 
FROM table;

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

Upvotes: 9

Ali Hashemi
Ali Hashemi

Reputation: 3368

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.

Upvotes: 6

Alexander Ushakov
Alexander Ushakov

Reputation: 5399

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

Upvotes: 3

Erik
Erik

Reputation: 101

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.

Upvotes: 10

fred
fred

Reputation: 31

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;'

Upvotes: 3

Srinivas Mutyala
Srinivas Mutyala

Reputation: 21

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

Upvotes: 2

aroth
aroth

Reputation: 54806

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

Upvotes: 9

Matthew Montgomery
Matthew Montgomery

Reputation: 81

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

Upvotes: 8

David
David

Reputation: 1187

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.

Upvotes: 7

Related Questions