SQL查询超时的设置方法

为了优化OceanBase的query timeout设置方式,特调研MySQL关于timeout的处理,记录如下。


mysql> show variables like '%time%';
+----------------------------+-------------------+
| Variable_name              | Value             |
+----------------------------+-------------------+
| connect_timeout            | 10                |
| datetime_format            | %Y-%m-%d %H:%i:%s |
| delayed_insert_timeout     | 300               |
| flush_time                 | 1800              |
| innodb_lock_wait_timeout   | 50                |
| innodb_old_blocks_time     | 0                 |
| innodb_rollback_on_timeout | OFF               |
| interactive_timeout        | 28800             |
| lc_time_names              | en_US             |
| lock_wait_timeout          | 31536000          |
| long_query_time            | 10.000000         |
| net_read_timeout           | 30                |
| net_write_timeout          | 60                |
| slave_net_timeout          | 3600              |
| slow_launch_time           | 2                 |
| system_time_zone           |                   |
| time_format                | %H:%i:%s          |
| time_zone                  | SYSTEM            |
| timed_mutexes              | OFF               |
| timestamp                  | 1366027807        |
| wait_timeout               | 28800             |
+----------------------------+-------------------+
21 rows in set, 1 warning (0.00 sec)


重点解释其中几个参数:

connect_timeout: 

The number of seconds that the mysqld server waits for a connect packet before respondingwith Bad handshake. The default value is 10 seconds as of MySQL 5.1.23 and 5 seconds before that.  Increasing the connect_timeout value might help if clients frequently encounter errors of the form Lost connection to MySQL server at ‘XXX’, system error: errno.
解释:在获取链接时,等待握手的超时时间,只在登录时有效,登录成功这个参数就不管事了。主要是为了防止网络不佳时应用重连导致连接数涨太快,一般默认即可。


interactive_timeout:

The number of seconds the server waits for activity on an interactive connection before closing it. An interactive client is defined as a client that uses the CLIENT_INTERACTIVE option to mysql_real_connect(). See alsowait_timeout.

解释:一个持续SLEEP状态的线程多久被关闭。线程每次被使用都会被唤醒为acrivity状态,执行完Query后成为interactive状态,重新开始计时。wait_timeout不同在于只作用于TCP/IP和Socket链接的线程,意义是一样的。

MySQL可以配置连接的超时时间,这个时间如果做得太长,甚至到了10min,那么很可能发生这种情况,3000个链接都被占满而且sleep在哪,新链接进不来,导致无法正常服务。因此这个配置尽量配置一个符合逻辑的值,60s或者120s等等。

说人话:

命令行下面敲一个命令后,直至下一个命令到来之前的时间间隔为interactive_time,如果这个时间间隔超过了interactive_timeout,则连接会被自动断开,下一个命令失败。不过一般的mysql客户端都有自动重连机制,下一个命令会在重连后执行。

mysql> set interactive_timeout = 1;
Query OK, 0 rows affected (0.00 sec)


mysql> show session variables like '%timeout%';
+----------------------------+----------+
| Variable_name              | Value    |
+----------------------------+----------+
| connect_timeout            | 10       |
| interactive_timeout        | 1        |
| wait_timeout               | 28800    |
+----------------------------+----------+
10 rows in set (0.00 sec)

=====

mysql> set wait_timeout = 1;
Query OK, 0 rows affected (0.00 sec)
【去泡杯茶,等会儿】

mysql> show session variables like '%timeout%';
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    7
Current database: *** NONE ***


+----------------------------+----------+
| Variable_name              | Value    |
+----------------------------+----------+
| connect_timeout            | 10       |
| interactive_timeout        | 28800    |
| wait_timeout               | 28800    |
+----------------------------+----------+
10 rows in set (0.01 sec)



wait_timeout:
The number of seconds the server waits for activity on a noninteractive connection (连接上没有活动命令,可能是客户端喝咖啡去了。)before closing it. Before MySQL 5.1.41, this timeout applies only to TCP/IP connections, not to connections made through Unix socket files, named pipes, or shared memory.
On thread startup, the session wait_timeout value is initialized from the global wait_timeout value or from the global interactive_timeout value, depending on the type of client

这里顺带解释一下什么是non-interactive connection

> Non-Interactive Commands
Just do a quick look up on a table without logging into the client, running the query then logging back out again.
You can instead just type one line using the ' -e ' flag.

c:\mysql\bin\mysql -u admin -p myDatabase -e 'SELECT * FROM employee'


net_read_timeout / net_write_timeout
The number of seconds to wait for more data from a connection before aborting the read. Before MySQL 5.1.41, this timeout applies only to TCP/IP connections, not to connections made through Unix socket files, named pipes, or shared memory. When the server is reading from the client, net_read_timeout is the timeout value controlling when to abort. When the server is writing to the client, net_write_timeout is the timeout value controlling when to abort. See also slave_net_timeout.
On Linux, the NO_ALARM build flag affects timeout behavior as indicated in the description of the net_retry_count system variable.
解释:这个参数只对TCP/IP链接有效,分别是数据库等待接收客户端发送网络包和发送网络包给客户端的超时时间,这是在Activity状态下的线程才有效的参数
 


JDBC setQueryTimeout函数:

为了避免查询出现死循环,或时间过长等现象,而导致线程阻塞,在获得Statement的实例后,stmt.setQueryTimeout(10); 避免因为查询导致程序出现线程阻塞。

但昨天发现程序出现了,“ORA-01013: 用户请求取消当前的操作”的异常。手工执行出错SQL语句发现,这个语句耗时20多秒。因为setQueryTimeout(10),所以还没有执行完查询语句就抛出异常了。使用setQueryTimeout(10)时一定要把时间设置的长一些,如60秒以上。只要不导致线程长期阻塞,就可以。太短了容易抛出,“ORA-01013: 用户请求取消当前的操作”的异常

JDBC实现setQueryTimeout的原理:

class IfxCancelQueryImpl extends TimerTask
  implements IfmxCancelQuery
{
  IfxStatement stmt;
  Timer t = null;

  public void startCancel(IfxStatement paramIfxStatement, int paramInt)
    throws Exception
  {
    this.stmt = paramIfxStatement;
    this.t = new Timer(true);
    this.t.schedule(this, paramInt * 1000);
  }

  public void run()
  {
    try
    {
      this.stmt.cancel();
      this.t.cancel();
    }
    catch (SQLException localSQLException)
    {
      this.t.cancel();
      throw new Error(localSQLException.getErrorCode() + ":" + localSQLException.getMessage());
    }
  }
}

可见,query timeout是通过客户端解决方案来做的,服务器端无需知晓。通过一个timer线程来监控执行时间,如果执行时间超时,则会schedule run()函数。


Reference:   

http://wangwei.cao.blog.163.com/blog/static/10236252620111119115540534/

http://sls8204.blog.163.com/blog/static/62979632200741683453114/


OceanBase可以通过server端支持query timeout,可以设置query timeout并且不中断当前session。这一点比MySQL先进。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在ASP.NET中设置SQL查询超时时间,可以通过在代码中使用CommandTimeout属性来实现。CommandTimeout属性是SqlCommand对象的一个属性,用于设置SQL查询超时时间,单位为秒。 以下是一个示例代码: ```csharp using System.Data.SqlClient; // 创建连接字符串,包含数据库服务器名、数据库名以及身份验证信息等 string connectionString = "Data Source=your_server;Initial Catalog=your_database;User ID=your_username;Password=your_password"; // 创建SQL查询命令对象 using (SqlConnection connection = new SqlConnection(connectionString)) { using (SqlCommand command = new SqlCommand("SELECT * FROM your_table", connection)) { // 设置查询超时时间为30秒 command.CommandTimeout = 30; try { // 打开数据库连接 connection.Open(); // 执行SQL查询 SqlDataReader reader = command.ExecuteReader(); // 处理查询结果 while (reader.Read()) { // 处理每一行数据 } // 关闭数据阅读器和数据库连接 reader.Close(); connection.Close(); } catch (Exception ex) { // 处理异常 } } } ``` 以上代码中,创建了一个SqlConnection对象和一个SqlCommand对象,然后使用CommandTimeout属性将超时时间设置为30秒。接下来,通过Open方法打开数据库连接,使用ExecuteReader方法执行查询,并通过Read方法逐行读取数据,最后使用Close方法关闭数据阅读器和数据库连接。 如果SQL查询超过了指定的超时时间,将会抛出一个SqlException异常。在catch块中可以进行对异常的处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值