一.查询长时间不返回的原因
首先要执行下show processlist来查看各个线程的状态(是否在等待锁)
1.DML写锁导致其他线程对改表的读取被阻塞
当一个线程正在持有t表的DML写锁时,其他线程查询语句就会被阻塞,一直等到DML写锁释放才能执行。
这个63870上的线程的state是waiting for table metadata lock,即在等待DML元数据锁的释放。
解决:使用查询语句查出是哪个过程在阻塞,使用kill命令断开这个连接即可
select blocking_pid from sys.schema_table_lock_waits
2.等flush
我们执行select * from t_19 where id=1;这条查询语句时,一直不返回,检测processlist发现在等待flush。
从processlist中可以看出,有2个线程在等待flush,但是flush这个过程是很快的,为什么会阻塞住呢,因为这个flush线程想要flush时,发现有另一个线程正在执行查询,为什么这个线程在执行查询就会导致这个flush被阻塞?
FLUSH TABLE就是关闭打开的表,并且刷新查询缓存 ,如果有LOCK TABLES ... READ存在则不允许
但是从processlist可以看到,我的查询语句没有加读锁啊?
原因是这3条语句是在3个事务中执行的,可重复读或者串行化的隔离级别下,select语句会加共享读锁
总的来说就是事务A中的select sleep(1) from t_19;语句导致这个表加了共享读锁,然后事务B中的flush tables t_19;语句就被阻塞住了,因为它想关闭表,但是事务A的查询语句还没执行完,最后事务C中的 select * from t_19 where id=1;这条普通查询就被阻塞住了,因为在等待flush。
解决:把第一个查询停止就行了
3.等行锁
一个查询语句会被另一个线程对同一行数据上所获取的写锁阻塞。
二.查询慢的原因
1.没加索引导致扫描行数太多
2.一致性读的时候,数据的版本太多,需要一直回滚到当前事务应该看到的数据版本,导致查询慢
事务A开始
事务B开始
事务B执行update t set c=c+1 where id =1(100w次)
事务A执行select c from t where id =1(执行800ms后,得到结果:c=1)
事务A执行select c from t where id =1 lock in share mode(执行0.2ms,得到结果:c=1000001)
为什么第一个查询比第二个查询慢这么多?因为第二个查询加了s型锁,是当前读,直接读最新数据c=1000001
而第一个查询是快照读,而事务B的插入语句的结果对于事务A是不应该可见的(事务B未提交并且事务B在事务A开始后才开始),并且这个语句执行了太多次,每次都生成一个undolog条目,所以对于事务A来说,要一直根据undo log得到他能看到的数据版本,要不断回滚,这就导致了查询时间过长。