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://sls8204.blog.163.com/blog/static/62979632200741683453114/
OceanBase可以通過server端支援query timeout,可以設定query timeout並且不中斷當前session。這一點比MySQL先進。