Como matar automaticamente as consultas lentas do MySQL após N segundos?

12

Estou procurando um script bash bem testado (ou solução alternativa) para fazer isso, a fim de evitar que max_connection seja esgotado. Eu sei que ele está lutando contra os sintomas, mas realmente precisa de tal script como uma solução de curto prazo.

    
por alfish 24.06.2012 / 21:54

3 respostas

19

verifique o comando pt-kill do conjunto de ferramentas do percona .

e .. comece a monitorar seu sistema - munin , cactos com melhores modelos de cactos para o mysql , qualquer coisa para que você tenha uma ideia do que é indo. logging mysql slow queries será uma boa idéia também.

    
por 24.06.2012 / 22:06
11

Se você tem o MySQL 5.1 onde a lista de processos está no INFORMATION_SCHEMA, você pode fazer isso para gerar os comandos KILL QUERY em massa a partir do cliente mysql para consultas que duram mais de 20 minutos (1200 segundos):

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

Você pode fazer cláusulas WHERE no campo INFO para procurar uma consulta específica, o campo TIME em consultas longas ou o campo DB em um banco de dados específico.

Se você é root @ localhost, você deve ter privilégios totais para executar isso da seguinte forma

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

Você pode crontab da seguinte forma:

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

Aqui está outra variação:

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

BTW Você não tem que especificar um myDB, pois eu leio explicitamente a partir de information_schema.processlist como um nome de tabela totalmente qualificado.

Aqui está uma demonstração do que você deve ver. Para este exemplo, irei ecoar o comando KILL de todos os processos cujo tempo > 20000 segundos:

[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@***** ~]#

Eu tenho feito essa técnica nos últimos 5 anos. De fato, enviei esta resposta para o DBA StackExchange no ano passado e foi aceita .

    
por 25.06.2012 / 17:58
6

Encontrei o seguinte recortado por código :

Atualização 2013-01-14: Houve uma sugestão anônima de que isso é potencialmente perigoso e também pode matar processos de replicação. Portanto, use a seu próprio risco:

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
    
por 24.06.2012 / 22:38