MySQLでクエリをタイムアウトすることは可能ですか?
つまり、指定した時間を超えるクエリがあると、MySQLによって強制終了され、永遠を待つ代わりにエラーが返されます。
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ツールを実行できる必要があります。そうしないと、コマンドラインで資格情報を提供する必要があります。
次の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
MySQL 5.1以降では、ストアドプロシージャを作成して、「長期実行」の条件に一致するすべてのクエリについてinformation_schmea.PROCESSLISTテーブルをクエリし、カーソルを反復処理してそれらを削除できます。次に、イベントスケジューラでそのプロシージャを繰り返し実行するようにセットアップします。
私はそれがもう少し長いと思っていましたが、 this によると、
MySQL 5.7.4では、最上位の読み取り専用SELECTステートメントに対して、ミリ秒単位で指定されたサーバー側の実行時間制限を設定する機能が導入されました。
SELECT
MAX_STATEMENT_TIME = 1000 --in milliseconds
*
FROM table;
これは、読み取り専用のSELECTステートメントでのみ機能することに注意してください。
MySQLフォーラムには、これに関するいくつかのスレッドがあります。
この投稿 innodb_lock_wait_timeoutを使用してサーバーでタイムアウトを設定する方法の詳細。
プログラムで行う方法 (JDBCを使用している場合).
この古い質問には更新された答えが必要だと思います。
次のように、すべての読み取り専用GLOBAL
クエリにSELECT
タイムアウトを設定できます。
_SET GLOBAL MAX_EXECUTION_TIME=1000;
_
指定される時間はミリ秒単位です。
特定のクエリに対してのみタイムアウトが必要な場合は、次のようにインラインで設定できます。
SELECT /*+ MAX_EXECUTION_TIME(1000) */ my_column FROM my_table WHERE ...
MySQLは永遠を待つ代わりにエラーを返します。
このメソッドは、読み取り専用のSELECT
sでのみ機能することに注意してください。 SELECT
ステートメントが読み取り専用ではないと判断された場合、そのタイマーに設定されたタイマーはキャンセルされ、次のNOTEメッセージがユーザーに報告されます。
_Note 1908 Select is not a read only statement, disabling timer
_
サブクエリを持つステートメントの場合、トップSELECT
のみを制限します。ストアドプログラム内のSELECT
ステートメントには適用されません。ストアドプログラム内のSELECT
ステートメントで_MAX_EXECUTION_TIME
_ヒントを使用しても無視されます。
上記のegrepで「2000」が見つかるとは思いません。
IDを選択するだけでなく、そのような高級なシェルのすべてを避けてみてください:
mysql -e 'select id from information_schema.processlist where info is not null and time > 30;'
これが私のスクリプトです:
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
MySQL 5.7.8以降、SELECTステートメントの実行タイムアウトを定義する max_execution_time オプションがあります。