查询长时间不返回
在表t执行下面的sql语句:
select * from t where id=1;结果查询时间长时间不反悔。一般碰到这种情况,大概率是表t被锁住了,分析原因的时候,一般首先执行show processlist命令,查看当前语句处于什么状态。
然后根据每种状态,取分析他们产生的原因、如何复现、以及如何处理。
等MDL锁
使用show processlist命令查看到Waiting for table metadata lock。
这个状态表示的是,现在有一个线程正在表t上请求或者持有MDL写锁,把select语句堵住了。
解决这类问题的方法就是找到谁持有MDL写锁,然后把他kill掉。
先执行语句 select * from performance_schema.setup_instruments where name='wait/lock/metadata/sql/mdl',看一下ENABLED和TIMED是不是都是YES,只有两个都是YES的时候才能执行下面的操作。
查询sys.schema_table_lock_waits这张表,找到造成阻塞的process id,把这个连接用kill命令断开即可。
select blocking_pid from sys.schema_table_lock_waits;等flush
show processlist的状态是Waiting for table flush。表示现在正有一个线程要对表t做flush操作。
MySQL里面对表做flush操作的用法一般有两个:
flush tables t with read lock;
flush tables with read lock;指定表t表示只关闭表t,否则全部关闭。
但是正常这两个语句执行都很快,除非他们也被其他线程堵住了。
所以这个状态出现的情况可能是:有一个flush tables命令被别的语句堵住了,然后它又堵住了我们的select语句。
等行锁
要读取的行上,如果已经有一个事务在这行记录上持有一个写锁时,select语句就会被堵住。
解决方法就是找到谁占用了这个行的写锁,查询方法是:
mysql> select * from t sys.innodb_lock_waits where locked_table='`test`.`t`'\G找到之后,使用kill关掉即可。
查询慢
这里的慢并不是要等待锁资源这类的慢,而是执行过程中的慢。
一个最简单的例子就是
select * from t where c=50000 limit 1;而c字段上没有索引,这个语句只能走id主键顺序扫描,因此需要扫描50000行,扫描行数多,执行慢,这个很好理解。
但是现在有一条只扫描一行,但是执行也很慢的语句
select * from t where id = 1;但是使用下面的写法,就很快的语句
select * from t where id = 1 lock in share mode;那是因为事务是这样的:
A启动以一个事务,然后B执行update语句执行了100万次,生成了100万个回滚日志(undo log)。这样要读取100万个undo log之前的版本的数据,执行效率自然就慢了。
而lock in share mode是当前读,直接读取当前的结果,所以速度很快。