Как установить максимальное время выполнения запроса MySQL? - PullRequest
21 голосов
/ 06 января 2009

Я хотел бы установить максимальное время выполнения для SQL-запросов, таких как set_time_limit () в php. Как я могу это сделать?

Ответы [ 5 ]

21 голосов
/ 27 апреля 2014

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

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. ( источник )

8 голосов
/ 27 апреля 2014

Если вы используете собственный драйвер mysql (обычно начиная с php 5.3) и расширение mysqli , это можно сделать с помощью асинхронного запроса:

<?php

// Here's 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 - я не включил никакой логики тайм-аута в само соединение.

5 голосов
/ 20 апреля 2012

Вы можете найти ответ на этот другой S.O. вопрос:

MySQL - можно ли ограничить максимально допустимое время выполнения запроса?

задание cron, которое выполняется каждую секунду на сервере базы данных, подключается и выполняет что-то вроде этого:

  • ПОКАЗАТЬ ПРОЦЕСС
  • Найти все соединения с временем запроса, превышающим максимальное требуемое время
  • Запустить KILL [идентификатор процесса] для каждого из этих процессов
4 голосов
/ 10 января 2018

Пожалуйста, перепишите ваш запрос как

select /*+ MAX_EXECUTION_TIME(1000) */ * from table

0 голосов
/ 07 июля 2016

pt_kill имеет опцию для такого. Но это по требованию, а не постоянный мониторинг. Он делает то, что предложил @Rafa. Однако см. --sentinel для подсказки, как приблизиться к cron.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...