如何设置mysql查询的最大执行时间?

ngynwnxp  于 2023-05-16  发布在  Mysql
关注(0)|答案(6)|浏览(222)

我想为sql查询设置一个最大执行时间,比如php中的set_time_limit()。我该怎么办?

chhkpiq4

chhkpiq41#

我以为它已经存在了一段时间,但根据this
MySQL 5.7.4引入了为顶级只读SELECT语句设置服务器端执行时间限制的功能,以毫秒为单位。

SELECT 
/*+ MAX_EXECUTION_TIME(1000) */ --in milliseconds
* 
FROM table;

请注意,这只适用于只读SELECT语句。

**更新:**该变量在MySQL 5.7.4中增加,在MySQL 5.7.8中重命名为max_execution_time。(资料来源)

s5a0g9ez

s5a0g9ez2#

如果你使用的是mysql native driver(从php 5.3开始就很常见)和mysqli扩展,你可以通过一个异步查询来完成这个任务:

<?php

// Heres 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";

    // kill the thread to stop the query from continuing to execute on 
    // the server, because we are abandoning it.
    var_dump($mysqli->kill($mysqli->thread_id));
    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 -我没有在连接本身包含任何超时逻辑。

6psbrbz9

6psbrbz93#

请将您的查询改写为
select /*+ MAX_EXECUTION_TIME(1000) */ * from table
此语句将在指定时间后终止查询

wsewodh2

wsewodh24#

你可以在另一个命令上找到答案。问题:
MySQL - can I limit the maximum time allowed for a query to run?
在数据库服务器上每秒运行一次的cron作业,连接并执行如下操作:

  • 展会流程员
  • 查找查询时间大于所需最大时间的所有连接
  • 对每个进程运行KILL [processid]
lymnna71

lymnna715#

pt_kill有这样的选项。但它是按需进行的,而不是持续监测。它做了@Rafa建议的事情。但是,请参阅--sentinel,了解如何接近cron

jjhzyzn0

jjhzyzn06#

您可以从Linux命令行运行下面的一行程序,甚至可以将其插入crontab以定期运行。
这个例子将立即杀死所有运行至少1小时(3600秒)的SELECT查询:

mysql -e "SELECT group_concat(concat('KILL ',id,';') separator ' ') AS cmd FROM information_schema.processlist WHERE user NOT IN ('slave','replica') AND info LIKE 'SELECT %' AND time > 3600;" | grep KILL | mysql

从上面的内容来看,您可能需要替换:
NOT IN (["safe list" of mysql users you NEVER want to touch; e.g. replication users])
time > [N seconds for slow queries you want to target]
注意:盲目运行KILL命令会导致错误的效果。请谨慎使用!

相关问题