web-dev-qa-db-ja.com

N秒後に遅いMySQLクエリを自動的に強制終了する方法は?

Max_connectionが使い果たされるのを避けるために、十分にテストされたbashスクリプト(または代替ソリューション)を探しています。私はそれが症状と戦っていることを知っていますが、短期的な解決策としてそのようなスクリプトが本当に必要です。

16
alfish

perconaツールキットpt-kill コマンドを確認してください。

そして、システムの監視を開始します- munincacti with mysqlのためのより良いcactiテンプレート など、何が起こっているのかいくつかのアイデアが得られます。 mysqlのスロークエリをログに記録することもお勧めします。

21
pQd

プロセスリストがINFORMATION_SCHEMAにあるMySQL 5.1を使用している場合、これを実行して、20分(1200秒)より長く実行されるクエリに対して、mysqlクライアント内から一括でKILL QUERYコマンドを生成できます。

SELECT GROUP_CONCAT(CONCAT('KILL QUERY ',id,';') SEPARATOR ' ') KillQuery
FROM information_schema.processlist WHERE user<>'system user'
AND time >= 1200\G

INFOフィールドに対してWHERE句を実行して特定のクエリを検索したり、TIMEフィールドを長時間実行されたクエリに対して検索したり、DBフィールドを特定のデータベースに対して検索したりできます。

Root @ localhostの場合は、次のように実行するための完全な権限が必要です。

SECONDS_TOO_LONG=1200
KILLPROC_SQLSTMT="SELECT GROUP_CONCAT(CONCAT('KILL QUERY ',id,';') SEPARATOR ' ') KillQuery FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"
mysql -uroot -ppassword -ANe"${KILLPROC_SQLSTMT}" | mysql -uroot -ppassword

これは次のようにcrontabできます。

SECONDS_TOO_LONG=1200
QUERIES_RUNNING_TOO_LONG=`mysql -uroot -ppassword -ANe"SELECT COUNT(1) FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"`
if [ ${QUERIES_RUNNING_TOO_LONG} -gt 0 ]
then
    KILLPROC_SQLSTMT="SELECT GROUP_CONCAT(CONCAT('KILL QUERY ',id,';') SEPARATOR ' ') KillQuery FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"
    mysql -uroot -ppassword -ANe"${KILLPROC_SQLSTMT}" | mysql -uroot -ppassword
fi

ここに別のバリエーションがあります:

SECONDS_TOO_LONG=1200
QUERIES_RUNNING_TOO_LONG=`mysql -uroot -ppassword -ANe"SELECT COUNT(1) FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"`
if [ ${QUERIES_RUNNING_TOO_LONG} -gt 0 ]
then
    KILLPROC_SQLSTMT="SELECT CONCAT('KILL QUERY ',id,';') KillQuery FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"
    mysql -uroot -ppassword -ANe"${KILLPROC_SQLSTMT}" > /tmp/kill_log_queries.sql
    mysql -uroot -ppassword < /tmp/kill_log_queries.sql
fi

ところで、私は明示的にinformation_schema.processlistから完全修飾テーブル名として読み取ったので、myDBを指定する必要はありません。

ここにあなたが見るべきもののデモンストレーションがあります。この例では、時間が20000秒を超えるすべてのプロセスのKILLコマンドをエコーし​​ます。

[root@***** ~]# mysql `lwdba_connect` -ANe"SELECT GROUP_CONCAT('KILL ',id,'; ' SEPARATOR ' ') FROM information_schema.processlist WHERE time > 25000 AND user<>'system user';"
+----------------------------------------------------+
| KILL 180186;  KILL 180141;  KILL 176419;  KILL 3;  |
+----------------------------------------------------+
[root@***** ~]#

私はこのテクニックを過去5年間行ってきました。 実際、昨年私はこの回答をDBA StackExchangeに提出し、それが受け入れられました

12
RolandoMySQLDBA

私は次のコードを省略した here を見つけました:

更新2013-01-14:これは潜在的に危険であり、レプリケーションプロセスも強制終了する可能性があるという匿名のヒントがありました。したがって、自己責任で使用してください。

mysql -e 'show processlist\G' |\
egrep -b5 'Time: [0-9]{2,}' |\
grep 'Id:' |\
cut -d':' -f2 |\
sed 's/^ //' |\
while read id
do
  mysql -e "kill $id;"
done
6
Nils

MySQL 5.7以降では、max_execution_time変数を使用して、すべての「SELECT」読み取りクエリに対してこれを自動的に実行できます。

1
Pawan Gaur

稼働時間が好きなら、私はbashソリューションを試しません!

コードにアクセスできる場合は、概説されたメソッド here を使用して、SELECTステートメントの最大実行時間を実際に設定できます。

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

それ以外の場合は、サーバー上で:

https://stackoverflow.com/questions/415905/how-to-set-a-maximum-execution-time-for-a-mysql-query

Pt-killをインストールします。

$ wget percona.com/get/pt-kill

プロセスリストのスナップショットを撮ります:

$ mysql -u root -B -pmyreallyimportantpassword -e "show processlist;" > processlist.txt

スナップショットでpt-killをテストします。

$ ./pt-kill --test-matching processlist.txt --busy-time 45 --kill-busy-commands 'Execute' --victims all --print
# 2019-02-25T17:34:37 KILL 45710302 (Execute 374 sec) SELECT\n\tCOUNT(DISTINCT(LP.sessionId))\nFROM lp_traffic LP\nINNER JOIN orders O ON O.orderId = LP.order
# 2019-02-25T17:34:37 KILL 45713515 (Execute 67 sec) SELECT \n\tCOUNT(DISTINCT(CASE WHEN T.response = 'SUCCESS' AND T.isVoid = 0 AND (T.txnType IN

一致ルールがあなたのケースに合っていることを確認してください。これらは、45秒以上すべての実行ステートメントを強制終了します。確認したら、このコマンドを変更して実行し、10秒間隔でステートメントを実行します。

$ ./pt-kill -u root -p myreallyimportantpassword --busy-time 45 --kill-busy-commands 'Execute' --victims all --interval 10 --kill
0
Geoff_Clapp