通过故意构造一些慢查询,看看两个会话之间的互相影响。
一 测试的初始环境
创建一个测试表
CREATE TABLE `test1` (
`id` int(11) DEFAULT NULL,
`n1` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
一开始表中有5行数据:
1 a
2 b
3 c
4 d
5 e
测试1
会话A中开启一个慢查询
[SQL]select * from test1 where sleep(1)=0;
受影响的行: 0
时间: 5.003s
在执行每一行时停1s,共5行,所以总执行时间5秒多一点。
会话A:
select * from test1 where sleep(2)=0;
会话B中尝试进行修改操作
update test1 set n1=CONCAT(n1,'-t') where id = 1;
发现会话B的修改操作不会被会话A阻塞
会话A:
select * from test1 where sleep(2)=0 for update;
会话B中尝试进行修改操作
[SQL]update test1 set n1=CONCAT(n1,'-t') where id = 1;
受影响的行: 1
时间: 7.646s
可以看到会话B被会话A阻塞了,移动鼠标从会话A切换到会话用了两秒多。
会话A:
begin;
select * from test1 where sleep(10)=0 for update;
commit;会话B中尝试进行修改操作
查看被锁住的表:
show open tables where in_use>0;
[SQL]update test1 set n1=CONCAT(n1,'-t') where id = 1;
受影响的行: 1
时间: 47.399s
可以看到会话B被会话A阻塞了
会话A:
select count(*) from test1 where sleep(2)=0;
会话B中尝试进行修改操作
[SQL]update test1 set n1=CONCAT(n1,'-t') where id = 1;
受影响的行: 1
时间: 0.184s
可以看到会话B未被会话A阻塞。
会话A:
select count(*) from test1 where sleep(2)=0;
会话B中尝试进行插入操作
[SQL]insert into test1(id,n1) values(6,'f');
受影响的行: 1
时间: 0.201s
可以看到会话B未被会话A阻塞。
小结一下:如果慢查询不带 for update 便不会阻塞修改操作
开启慢查询日志:
show variables like 'slow_query%';
show variables like 'long_query_time';
set global slow_query_log='ON';
执行以上的慢查询后检查慢查询日志文件,看到如下的结果
Mysql5.5, Version: 5.5.33-log (MySQL Community Server (GPL)). started with:
TCP Port: 3306, Named Pipe: /tmp/mysql.sock
Time Id Command Argument
# Time: 181218 19:17:39
# User@Host: root[root] @ localhost [127.0.0.1]
# Query_time: 14.003255 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 7
use test;
SET timestamp=1545131859;
select count(*) from test1 where sleep(2)=0;
可见确实产生了一个慢查询记录。
特地将mysql服务关闭后又重新启动,发现慢查询日志文件保持不变。也就是说重启mysql服务不会自动删除慢查询日志文件。
测试2
会话A: 是一个很慢的修改数据操作
[SQL]update test1 set n1=CONCAT(n1,'-t') where sleep(2)=0;
受影响的行: 7
时间: 14.112s;
会话B中尝试进行求记录数
[SQL]
select count(*) from test1 ;
受影响的行: 0
时间: 0.000s
可以看到会话B未被会话A阻塞。
会话A: 是一个很慢的修改数据操作
[SQL]update test1 set n1=CONCAT(n1,'-t') where sleep(2)=0;
受影响的行: 7
时间: 14.112s;
会话B中尝试进行求记录数
[SQL]
select count(*) from test1 where n1>'';
受影响的行: 0
时间: 0.001s
可以看到会话B未被会话A阻塞。
查看慢查询日志文件:
Mysql5.5, Version: 5.5.33-log (MySQL Community Server (GPL)). started with:
TCP Port: 3306, Named Pipe: /tmp/mysql.sock
Time Id Command Argument
# Time: 181218 19:17:39
# User@Host: root[root] @ localhost [127.0.0.1]
# Query_time: 14.003255 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 7
use test;
SET timestamp=1545131859;
select count(*) from test1 where sleep(2)=0;
Mysql5.5, Version: 5.5.33-log (MySQL Community Server (GPL)). started with:
TCP Port: 3306, Named Pipe: /tmp/mysql.sock
Time Id Command Argument
# Time: 181218 19:48:22
# User@Host: root[root] @ localhost [127.0.0.1]
# Query_time: 14.010628 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 7
use test;
SET timestamp=1545133702;
update test1 set n1=CONCAT(n1,'-t') where sleep(2)=0;
# Time: 181218 19:48:36
# User@Host: root[root] @ localhost [127.0.0.1]
# Query_time: 14.010784 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 7
SET timestamp=1545133716;
update test1 set n1=CONCAT(n1,'-t') where sleep(2)=0;
确实看到update操作用时14s多。
小结一下: 尽管有一个很慢的修改操作正在更新数据表,但不会因此而阻塞查询操作。
测试3
会话A: 是一个很慢的修改数据操作
[SQL]update test1 set n1=CONCAT(n1,'-t') where sleep(2)=0;
受影响的行: 7
时间: 14.229s
会话B中尝试进行求记录数,并且带上了For update
[SQL]
[SQL]select count(*) from test1 where n1>'' for update;
受影响的行: 0
时间: 11.532s
可以看到会话B被会话A阻塞。
会话A 一个很慢的查询求最大值,并且带有for update
[SQL]select max(id) from test1 where SLEEP(2) = 0 for update;
受影响的行: 0
时间: 14.003s
会话B 一个很慢的查询求最大值,并且带有for update
[SQL]select max(id) from test1 where SLEEP(2) = 0 for update;
受影响的行: 0
时间: 25.115s
可以看到会话B被会话A阻塞。
会话A 一个很慢的查询求最大值,并且带有for update
[SQL]select max(id) from test1 where SLEEP(2) = 0 for update;
受影响的行: 0
时间: 14.003s
会话B 一个很慢的查询求最大值,不带for update
[SQL]select max(id) from test1 where SLEEP(2) = 0
受影响的行: 0
时间: 14.004s
可以看到会话B没有被会话A阻塞。
会话A 一个很慢的查询求最大值,并且带有for update
[SQL]select max(id) from test1 where SLEEP(2) = 0 for update;
受影响的行: 0
时间: 14.005s
会话B: 是一个修改数据操作
[SQL]update test1 set n1=CONCAT(n1,'-t') where id = 1;
受影响的行: 1
时间: 11.956s
会话C中尝试进行求记录数,并且带上了For update
[SQL]select max(id) from test1 where SLEEP(2) = 0 for update;
受影响的行: 0
时间: 23.801s
可以看到会话B被会话A阻塞,会话C被会话A,B阻塞。会话c的阻塞时间差不多是A,C执行时间之和。
小结一下:慢查询如果带 for update 便会阻塞其后的带for update的查询操作以及修改操作。不带for update的查询不会被阻塞。