Подтвердить что ты не робот

Как я могу остановить MySQL-запрос, если он занимает слишком много времени?

Возможно ли запрограммировать запрос в MySQL?

То есть, если какой-либо запрос превышает указанное мной время, он будет убит MySQL и он вернет ошибку, а не ждет вечность.

4b9b3361

Ответ 1

В CPAN есть хороший Perl script, чтобы сделать это: 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 инструктирует script убить соответствующие процессы.

Пользователь root должен иметь возможность запускать локальные средства mysql без проверки подлинности, иначе вам нужно будет предоставить учетные данные в командной строке.

Ответ 2

Я просто установил следующее bash script как задание 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

Ответ 3

Начиная с MySQL 5.1 вы можете создать хранимую процедуру для запроса таблицы information_schmea.PROCESSLIST для всех запросов, которые соответствуют вашим критериям для "длительной работы", а затем перебрать курсор, чтобы убить их. Затем настройте эту процедуру для выполнения на регулярной основе в планировщике событий.

Смотрите: http://forge.mysql.com/tools/tool.php?id=106

Ответ 4

Я думал, что это было вокруг немного дольше, но согласно этому,

MySQL 5.7.4 вводит возможность устанавливать ограничения времени выполнения на стороне сервера, указанные в миллисекундах, для операторов SELECT только для чтения.

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

Обратите внимание, что это работает только для операторов SELECT только для чтения.

Ответ 6

Я не думаю, что egrep выше нашел бы "2000".
Почему бы не попробовать просто выбрать идентификатор, а также избежать всего этого шикарного материала оболочки:

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

Ответ 7

Вот мой script:

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

Ответ 8

Так как MySQL 5.7.8 содержит max_execution_time параметр, определяющий тайм-аут выполнения для операторов SELECT.

Ответ 9

Я думаю, что этот старый вопрос нуждается в обновленном ответе.

Вы можете установить тайм-аут GLOBAL для всех ваших запросов SELECT только для чтения:

SET GLOBAL MAX_EXECUTION_TIME=1000;

Время указано в миллисекундах.

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

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

MySQL возвращает ошибку вместо ожидания вечности.

Обратите внимание, что этот метод работает только для чтения SELECT s. Если инструкция SELECT определяется как не доступная только для чтения, то любой установленный для нее таймер отменяется, и пользователю сообщается следующее сообщение ПРИМЕЧАНИЕ:

Note 1908 Select is not a read only statement, disabling timer

Для операторов с подзапросами он ограничивает только верхний SELECT. Это не относится к операторам SELECT в хранимых программах. Использование инструкций MAX_EXECUTION_TIME в SELECT в хранимой программе будет проигнорировано.

Ответ 10

Чтобы убить запросы на основе их thread_id, попробуйте выполнить запрос и убейте их вручную,

SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Query' AND TIME > 10;

Альтернативным и интерактивным подходом было бы вывести значения в файл с помощью запроса,

SELECT CONCAT('KILL ',ID,';')
FROM   INFORMATION_SCHEMA.PROCESSLIST
WHERE  USER = ‘new’
   AND COMMAND = 'Query'
   AND TIME > 10
  INTO   OUTFILE '/tmp/thread_kill.txt';

а затем уничтожьте потоки в файле, используя

 \. /tmp/thread_kill.txt

Другая альтернатива - искать инструменты мониторинга, такие как MONyog, MySQL Enterprise Monitor, Percona toolkit, где вы можете позволить инструменту искать более длинные/медленные запросы, блокировать запросы и убивать их. С MONyog добавленное преимущество заключается в том, что медленные запросы нельзя просто убить, а также проинформировать пользователя по электронной почте о том, какой запрос задерживал ресурсы и сделал сервер медленным.