开发者

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

开发者 https://www.devze.com 2022-12-17 22:09 出处:网络
Is it possib开发者_开发问答le 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.The

Is it possib开发者_开发问答le 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.


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.


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


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.


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


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.


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.


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


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


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

0

精彩评论

暂无评论...
验证码 换一张
取 消