1、MySQL 提供了 睡眠函数sleep
官方介绍如下:
SLEEP(duration)
Sleeps (pauses) for the number of seconds given by the duration argument, then returns 0. The duration may have a fractional part. If the argument is NULL or negative, SLEEP() produces a warning, or an error in strict SQL mode.
When sleep returns normally (without interruption), it returns 0
妙用一: 用在select 语句中
sleep 可以用于 select 字段处与where 处
比如:
select sleep(10),field1,field2 from t;
select field1 from t where sleep(20);
有了这个操作之后,我们有时候模拟慢查询就方便多了。
我在实际业务中有以下两种情况用到了sleep函数
a、模拟慢查询以复现生产中 查询慢造成的并发问题
在session1中 执行
select sleep(10),field1 from t
在session2中 执行 你需要模拟的并发语句,update、delete、ddl语句
你就可以复现 元数据锁的等待时间了。是必须整个select 语句执行完,ddl才能拿到元数据锁执行
这么写的好处是你可以决定慢查询要执行的时间。
b、解决开发在写参数化语句过程中不好跟踪的问题
有时后端开发参数化的语句不好跟踪。总是认为是MySQL的bug 为了看到最终的语句。我让开发在select 语句中加上sleep,然后在慢查询日志中就很快能找到此语句了。
妙用二: 用在update语句中
前几天在研究当表结构都没有索引的时候,udpate语句执行锁的情况。利用到了sleep特性
下面花一点篇幅来说说整个过程
在RC隔离级别下。无索引的update 执行情况
将当前session换为RC级别,并确认
set session transaction isolation level read committed;
select @@transaction_isolation;
创建测试表并构建基础数据
CREATE TABLE `billno` (
`tid` int(10) unsigned NOT NULL,
`billtype` int(10) unsigned NOT NULL COMMENT '单据类型ID',
`datas` int(10) unsigned NOT NULL COMMENT '如果永不归零则为0,如果跨年则为年份2016 ,如果跨月则为201601,如果跨日则为20160103',
`maxno` int(10) unsigned NOT NULL COMMENT '当前系统里面最大的单据ID'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='单据编号生成表';
insert into billno
values(1,1,1,1),(2,2,2,2),(3,3,3,3),(4,4,4,4)
,(5,5,5,5),(6,6,6,6),(7,7,7,7),(8,8,8,8)
,(9,9,9,9);
ALTER TABLE `billno` ADD PRIMARY KEY (`tid`,`billtype`,`datas`);
然后执行一个update语句,利用sleep特性。让每行都执行得很慢 让每行都执行很慢。这个很关键
session1中执行
update billno set tid =19 where sleep(20) or maxno =9
然后在session2中 每隔几秒执行一次查询
select * from performance_schema.data_locks;
第一次查

第二次查

最后一次查

可以从上面的结果看出 当没有索引的情况找到符合条件的行时候 在RC情况下是这一行没有最终修改 那么将很快释放掉锁。
我们把session1语句改这样
session1中执行
update billno set tid =19 where sleep(20) and maxno =9
又在 session2中查询
select * from performance_schema.data_locks;

当在RC级别下。最终只会锁符合where 条件的行,不符合条件的行只会在扫描的时候短暂加一下锁。
在RR隔离级别下。无索引的update 执行情况
set session transaction isolation level read committed;
select @@transaction_isolation;
同样的语句。只是隔离级别换成了RR
session1中执行
update billno set tid =19 where sleep(20) or maxno =9
然后在session2中 每隔几秒执行一次查询
select * from performance_schema.data_locks;
第一次查

第二次查

最后一次查

可以从上面的结果看出 当没有索引的情况找到符合条件的行时候 在RR情况下扫描的每行都加上了锁,直到语句结束。
再来测试第二个语句
session1中执行
update billno set tid =19 where sleep(20) and maxno =9
同样在session2中查询

可以从上面的结果看出 当没有索引的情况即使条件不符合 在RR情况下扫描的每行都加上了锁,直到语句结束。
结论 可以看到RR级别的锁明显多于RC 所以生产环境不是必须要RR那就用RC吧




