max_statement_time 选项
如果未添加 MAX_EXECUTION_TIME() 优化器提示,则 max_execution_time 选项指定只读 SELECT 语句的超时时间。
该值以毫秒为单位。
该选项存在于 GLOBAL 和 SESSION 级别,并且可以动态更改。
GLOBAL 值用作 SESSION 值的默认值。
值 0 表示没有超时生效。
mysql> connect Connection id: 5 Current database: *** NONE *** mysql> SELECT @@global.max_statement_time, @@session.max_statement_time; +-----------------------------+------------------------------+ | @@global.max_statement_time | @@session.max_statement_time | +-----------------------------+------------------------------+ | 1000 | 1000 | +-----------------------------+------------------------------+ 1 row in set (0.00 sec)
mysql> SET SESSION max_statement_time = 2000; -- 2 seconds Query OK, 0 rows affected (0.00 sec) mysql> SELECT @@global.max_statement_time, @@session.max_statement_time; +-----------------------------+------------------------------+ | @@global.max_statement_time | @@session.max_statement_time | +-----------------------------+------------------------------+ | 1000 | 2000 | +-----------------------------+------------------------------+ 1 row in set (0.00 sec)
一个耗时 1.5 秒的查询成功:
mysql> SELECT SLEEP(1.5); +------------+ | SLEEP(1.5) | +------------+ | 0 | +------------+ 1 row in set (1.51 sec)
超过 2 秒的查询失败:
mysql> SELECT SLEEP(5); +----------+ | SLEEP(5) | +----------+ | 1 | +----------+ 1 row in set (2.02 sec)
仅 SELECT 语句受到影响:
mysql> DO SLEEP(5); Query OK, 0 rows affected (5.00 sec)
MySQL 5.7 及更高版本的 SELECT 语句
从 MySQL 5.7.4 开始,支持只读 SELECT 语句的自动超时(以下讨论假设 5.7.8 或者更高版本,因为该功能对选项/提示名称和语法进行了更改)。
有两种方法可以设置只读 SELECT 语句允许执行多长时间的上限:
- max_execution_time 选项
- SELECT 语句的 MAX_EXECUTION_TIME() 优化器提示
以下适用:
- 只有只读的 SELECT 语句会受到影响。
- 只有顶层(即不是子查询)受到影响。
- 存储程序中的 SELECT 语句不受影响(存储程序中不支持 MAX_EXECUTION_TIME() 提示)。
下面将讨论这两个选项。
在这篇文章中,我们将了解如果我们需要自动终止长时间运行的查询,可以使用哪些选项。
所有版本和所有语句类型
重要提示:如果我们正在更改非事务性表(例如 MyISAM 表)中的数据,则终止查询不会回滚事务。
这意味着数据将处于未知状态,其中部分应用了该语句的效果。
如果使用复制,则需要重建副本。
一般来说,对于非事务性引擎,最好让语句运行。
在 MySQL 5.7.4 之前,没有内置方法来自动终止长时间运行的查询。
相反,可以使用以下两种解决方案之一:
- 编写一个脚本,定期检查是否有任何长时间运行的查询,并在需要时终止它们。
- 编写一个可以使用事件调度程序执行的存储过程。此选项仅在 MySQL 5.1 及更高版本中可用,因为早期版本不支持事件。
两者的工作方式非常相似。
第一个的优点是我们可以选择我们选择的编程语言,而存储过程/事件解决方案将所有内容都保存在数据库中。
要实施检查,我们需要使用进程列表。
在 MySQL 5.1 及更高版本中,我们可以使用 information_schema.PROCESSLIST 表,它可以从标准 SELECT 查询中获取进程列表,如果解决方案是在存储过程中实现的,则这是必要的。
在 MySQL 5.6 和更高版本中,可以使用 performance_schema.threads 表(并且通常首选,因为它需要比 SHOW PROCESSLIST 或者 information_schema.PROCESSLIST 更少的锁)。
对于 InnoDB,我们甚至可能对长时间运行的事务感兴趣。
这些可以通过信息模式中的 INNODB_TRX 进行监控。
INNODB_TRX 表包括事务开始的时间。
我们可能还需要考虑是否有任何其他查询正在等待长时间运行的查询持有的锁。
对于 InnoDB 表,可以使用信息模式中的 INNODB_LOCK_WAITS 和 INNODB_TRX 表轻松检查。
InnoDB Information Schema 表从 MySQL 5.1 和 InnoDB Plugin 和 MySQL 5.5 及更高版本开始可用。
虽然长时间运行的查询和事务通常不好,因为它们可能会阻塞其他连接并增加资源的使用,但某些查询不可避免地需要很长时间,例如大表的表重建,批量导入等. 因此,我们可能需要考虑一种方法来标记我们不想终止的查询;例如,这可以通过查询开头的注释来实现。
注意:确保我们测试解决方案。
上述参考资料只是示例,旨在作为如何开始的建议,不应被视为生产就绪解决方案。
SELECT 语句的 MAX_STATEMENT_TIME 子句
MAX_EXECUTION_TIME() 优化提示可用于更改特定查询的超时。
例如,如果 max_execution_time 设置为 1 秒,但我们知道给定查询需要 5 秒,那么我们可以更改超时:
mysql> SELECT @@global.max_execution_time, @@session.max_execution_time; +-----------------------------+------------------------------+ | @@global.max_execution_time | @@session.max_execution_time | +-----------------------------+------------------------------+ | 1000 | 1000 | +-----------------------------+------------------------------+ 1 row in set (0.00 sec)
mysql> SELECT /*+ MAX_EXECUTION_TIME(6000) */ /* may take up to 5+ seconds - don't kill */ SLEEP(5); +----------+ | SLEEP(5) | +----------+ | 0 | +----------+ 1 row in set (5.00 sec)
或者我们可以使用它来降低超时时间:
mysql> SELECT /*+ MAX_EXECUTION_TIME(500) */ /* may take up to 5+ seconds - don't kill */ SLEEP(5); +----------+ | SLEEP(5) | +----------+ | 1 | +----------+ 1 row in set (0.50 sec