web-dev-qa-db-ja.com

時間がかかりすぎる場合、どうすればMySQLクエリを停止できますか?

MySQLでクエリをタイムアウトすることは可能ですか?

つまり、指定した時間を超えるクエリがあると、MySQLによって強制終了され、永遠を待つ代わりにエラーが返されます。

44
acheruns

CPANには、これを行うための素敵なPerlスクリプトがあります。 http://search.cpan.org/~rsoliv/mysql-genocide-0.03/mysql-genocide

適切なパラメーターで実行するようにスケジュールするだけです。 CRONtabファイル/ etc/cron.d/mysql_query_timeoutを作成して、毎分実行するようにスケジュールします。

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

7200は、秒単位の最大許容実行時間です。 -sスイッチは、SELECTクエリを除くすべてを除外します。 -Kスイッチは、一致するプロセスを強制終了するようにスクリプトに指示します。

Rootユーザーは、認証なしでローカルのmysqlツールを実行できる必要があります。そうしないと、コマンドラインで資格情報を提供する必要があります。

10
Erik

次のbashスクリプトをcronジョブとして設定して、MySQL 5.0でこれを実現します(30秒以上実行されているクエリをすべて削除します)。誰にとっても有用であることが判明した場合にここで共有します(私のbashスクリプトスタイルが非効率的または凶悪な場合、それは私の主要な開発言語ではありません):

#!/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
9
aroth

MySQL 5.1以降では、ストアドプロシージャを作成して、「長期実行」の条件に一致するすべてのクエリについてinformation_schmea.PROCESSLISTテーブルをクエリし、カーソルを反復処理してそれらを削除できます。次に、イベントスケジューラでそのプロシージャを繰り返し実行するようにセットアップします。

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

8

私はそれがもう少し長いと思っていましたが、 this によると、

MySQL 5.7.4では、最上位の読み取り専用SELECTステートメントに対して、ミリ秒単位で指定されたサーバー側の実行時間制限を設定する機能が導入されました。

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

これは、読み取り専用のSELECTステートメントでのみ機能することに注意してください。

8
Westy92

MySQLフォーラムには、これに関するいくつかのスレッドがあります。

この投稿 innodb_lock_wait_timeoutを使用してサーバーでタイムアウトを設定する方法の詳細。

プログラムで行う方法 (JDBCを使用している場合).

7
David

この古い質問には更新された答えが必要だと思います。

次のように、すべての読み取り専用GLOBALクエリにSELECTタイムアウトを設定できます。

_SET GLOBAL MAX_EXECUTION_TIME=1000;_

指定される時間はミリ秒単位です。

特定のクエリに対してのみタイムアウトが必要な場合は、次のようにインラインで設定できます。

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

MySQLは永遠を待つ代わりにエラーを返します。

このメソッドは、読み取り専用のSELECTsでのみ機能することに注意してください。 SELECTステートメントが読み取り専用ではないと判断された場合、そのタイマーに設定されたタイマーはキャンセルされ、次のNOTEメッセージがユーザーに報告されます。

_Note 1908 Select is not a read only statement, disabling timer_

サブクエリを持つステートメントの場合、トップSELECTのみを制限します。ストアドプログラム内のSELECTステートメントには適用されません。ストアドプログラム内のSELECTステートメントで_MAX_EXECUTION_TIME_ヒ​​ントを使用しても無視されます。

3
Ali Hashemi

上記のegrepで「2000」が見つかるとは思いません。
IDを選択するだけでなく、そのような高級なシェルのすべてを避けてみてください:

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

これが私のスクリプトです:

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
2

MySQL 5.7.8以降、SELECTステートメントの実行タイムアウトを定義する max_execution_time オプションがあります。

2