Как установить максимальное время выполнения для запроса mysql?
Я хотел бы установить максимальное время выполнения для sql-запросов, таких как set_time_limit() в php. Как я могу сделать?
Ответы
Ответ 1
Я думал, что это было немного дольше, но в соответствии с этим,
MySQL 5.7.4 предоставляет возможность устанавливать ограничения времени выполнения на стороне сервера, заданные в миллисекундах, для операторов SELECT только для чтения верхнего уровня.
SELECT
/*+ MAX_EXECUTION_TIME = 1000 */ --in milliseconds
*
FROM table;
Обратите внимание, что это работает только для операторов SELECT только для чтения.
Обновление: эта переменная была добавлена в MySQL 5.7.4 и переименована в max_execution_time
в MySQL 5.7.8. (источник)
Ответ 2
Если вы используете собственный драйвер mysql (обычно начиная с php 5.3) и расширение mysqli, вы можете выполнить это с помощью асинхронного запроса:
<?php
// Here an example query that will take a long time to execute.
$sql = "
select *
from information_schema.tables t1
join information_schema.tables t2
join information_schema.tables t3
join information_schema.tables t4
join information_schema.tables t5
join information_schema.tables t6
join information_schema.tables t7
join information_schema.tables t8
";
$mysqli = mysqli_connect('localhost', 'root', '');
$mysqli->query($sql, MYSQLI_ASYNC | MYSQLI_USE_RESULT);
$links = $errors = $reject = [];
$links[] = $mysqli;
// wait up to 1.5 seconds
$seconds = 1;
$microseconds = 500000;
$timeStart = microtime(true);
if (mysqli_poll($links, $errors, $reject, $seconds, $microseconds) > 0) {
echo "query finished executing. now we start fetching the data rows over the network...\n";
$result = $mysqli->reap_async_query();
if ($result) {
while ($row = $result->fetch_row()) {
// print_r($row);
if (microtime(true) - $timeStart > 1.5) {
// we exceeded our time limit in the middle of fetching our result set.
echo "timed out while fetching results\n";
var_dump($mysqli->close());
break;
}
}
}
} else {
echo "timed out while waiting for query to execute\n";
var_dump($mysqli->close());
}
Флаги, которые я даю mysqli_query, выполняют важные задачи. Он говорит клиентскому драйверу включить асинхронный режим, в то же время заставляя нас использовать более подробный код, но позволяет нам использовать тайм-аут (а также выдавать параллельные запросы, если хотите!). Другой флаг говорит клиенту не буферизовать весь набор результатов в память.
По умолчанию php настраивает свои клиентские библиотеки mysql для извлечения всего результирующего набора вашего запроса в память, прежде чем он позволит вашему php-коду начать получать доступ к строкам в результате. Это может занять много времени для передачи большого результата. Мы отключаем его, в противном случае мы рискуем истечь время ожидания завершения буферизации.
Обратите внимание, что есть два места, где мы должны проверить превышение лимита времени:
- Фактическое выполнение запроса
- при получении результатов (данных)
Вы можете сделать подобное в PDO и обычном расширении mysql. Они не поддерживают асинхронные запросы, поэтому вы не можете установить тайм-аут на время выполнения запроса. Однако они поддерживают небуферизованные результирующие наборы, и поэтому вы можете по крайней мере реализовать тайм-аут при извлечении данных.
Для многих запросов mysql может начать потоковую передачу результатов вам практически сразу, и поэтому одни только небуферизованные запросы позволят вам несколько эффективнее реализовать тайм-ауты для определенных запросов. Например,
select * from tbl_with_1billion_rows
может начать потоковую передачу строк сразу, но,
select sum(foo) from tbl_with_1billion_rows
Необходимо обработать всю таблицу, прежде чем она сможет начать возвращать вам первую строку. Это последний случай, когда время ожидания асинхронного запроса спасет вас. Это также спасет вас от старых тупиков и прочего.
PS - Я не включил никакой логики тайм-аута на самом соединении.
Ответ 3
Вы можете найти ответ на этот другой S.O. Вопрос:
MySQL - могу ли я ограничить максимально допустимое время выполнения запроса?
задание cron, выполняемое каждую секунду на сервере базы данных, соединение и выполнение чего-то вроде этого:
- SHOW PROCESSLIST
- Найти все соединения с временем запроса, превышающим максимально возможное время.
- Запустите KILL [идентификатор процесса] для каждого из этих процессов.
Ответ 4
Пожалуйста, перепишите свой запрос, например
select /*+ MAX_EXECUTION_TIME(1000) */ * from table
Ответ 5
pt_kill
имеет такую возможность. Но он по требованию, а не постоянный мониторинг. Он делает то, что предложил @Рафа. Однако см. --sentinel
для того, чтобы приблизиться к cron
.
Ответ 6
Я не знаю, как это сделать в mysql, но поскольку вы знакомы с set_time_limit()
в php, почему бы не запустить SQL-запрос в PHP скрипт, чтобы ограничить время?