Как автоматически убить медленные MySQL запросы через N секунд?


16

Я ищу хорошо протестированный bash-скрипт (или альтернативное решение) для этого, чтобы избежать исчерпания max_connection. Я знаю, что это борется с симптомами, но действительно нужен такой сценарий, как краткосрочное решение.


Какую версию MySQL вы используете ???
RolandoMySQLDBA

версия mysql 5.5
alfish

Ответы:


21

проверьте команду pt-kill из набора инструментов Percona .

и ... начните контролировать свою систему - munin , cacti с лучшими шаблонами cacti для mysql , что угодно, чтобы вы поняли, что происходит. регистрация медленных запросов mysql также будет хорошей идеей.


Спасибо за предложения, но действительно ищите «одноразовый» скрипт.
Alfish

5
pt-kill очень хорошо протестирован и решает вашу проблему. Требуется около 10 минут, чтобы выяснить параметры командной строки и запустить его. Что вы еще хотите?
Аарон Браун

12

Если у вас есть MySQL 5.1, где список процессов находится в INFORMATION_SCHEMA, вы можете сделать это для генерации массовых команд KILL QUERY из клиента mysql для запроса, выполняющегося более 20 минут (1200 секунд):

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

Вы можете использовать предложения WHERE для поля INFO, чтобы искать конкретный запрос, поле 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

Кстати, вам не нужно указывать myDB, так как я явно прочитал из information_schema.processlist как полное имя таблицы.

Вот демонстрация того, что вы должны увидеть. В этом примере я выведу команду KILL для всех процессов, время которых> 20000 секунд:

[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 в прошлом году, и он был принят .


Роланд, не могли бы вы уточнить: является ли эта команда постоянной или ее нужно часто запускать? Что следует подставить в команду, если предположить, что пользователь mysql - «root», а имя базы данных - myDB? Спасибо
Alfish

Я обновил свой ответ.
RolandoMySQLDBA

Спасибо, но после преобразования вашего последнего рецепта в bash-скрипт я получаю: ОШИБКА 1064 (42000) в строке 1: у вас ошибка в синтаксисе SQL; проверьте руководство, соответствующее вашей версии сервера MySQL, чтобы найти правильный синтаксис для использования рядом с '' в строке 1
alfish

Какая команда SQL сгенерировала эту ошибку ???
RolandoMySQLDBA

Roland SF это не песочница. Лучше протестировать, прежде чем предлагать что-то в качестве решения. Кроме того, когда все соединения насыщены, как mysql собирается запустить вашу процедуру, предполагая, что она не является неисправной?
Alfish

6

Я нашел следующий фрагмент кода здесь :

Обновление 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

Какая постоянная времени в фрагменте выше?
Alfish

@alfish Я не автор, но я бы сказал, что это регулярное выражение, которое соответствует всем значениям времени, которые имеют по крайней мере две цифры. Таким образом, здесь предполагается, что 10 - это слишком долго.
Нильс

1

В MySQL 5.7 и далее вы можете использовать переменную max_execution_time, чтобы сделать это автоматически для всех запросов чтения SELECT.


0

Я не стал бы пробовать решения bash, если вам нравится uptime!

Если у вас есть доступ к коду, вы можете установить максимальное время выполнения операторов SELECT, используя метод, описанный здесь :

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

В противном случае на сервере:

/programming/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

Убедитесь, что правила матча соответствуют вашему случаю. Это выше убьет все операторы Execute за 45 секунд. Если вы уверены, измените и выполните эту команду, чтобы выполнить инструкцию с интервалом в 10 секунд:

$ ./pt-kill -u root -p myreallyimportantpassword --busy-time 45 --kill-busy-commands 'Execute' --victims all --interval 10 --kill
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.