解决mysql数据库锁表问题:Lock wait timeout exceeded; try restarting transaction (二)

版权声明:本文为博主原创文章,转载请注明出处,尊重劳动成果,谢谢~ https://blog.csdn.net/zhanglf02/article/details/86487214

今天在测试库执行一个update的脚本,结果执行半天没出来。一开始以为网络问题,执行结果慢,或者数据量大,要执行一会。结果是死活出不来了。连最简单的表查询都查不出来。最后这个update执行就报错了。
报错信息如下:

### Error updating database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: update     platform_front_category pfc1,platform_front_category pfc2    set     pfc1.id_temp=pfc2.id ,pfc1.modified=now()   where     pfc1.platform_id=pfc2.platform_id     and pfc1.level=pfc2.level and pfc1.name=pfc2.name      and pfc1.category_status=1 and pfc2.category_status=2;
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
; SQL []; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

先看下我这个更新的sql吧,目的是把platform_front_category 中的状态为2的id复制给对应的状态为1的id_temp字段。

		update 
			platform_front_category pfc1,platform_front_category pfc2 
		set 
			pfc1.id_temp=pfc2.id ,pfc1.modified=now()
		where 
			pfc1.platform_id=pfc2.platform_id 
			and pfc1.level=pfc2.level and pfc1.name=pfc2.name  
			and pfc1.category_status=1 and pfc2.category_status=2;

这个sql对于数据量小的表执行起来还行,但是对于数据量大的表就会有问题。这个sql需要优化。

先看这个sql导致问题的原因

分析原因有一个疑问点,还请看到这个问题,知道答案的人给回答一下:就是如何看mysql当前使用的是那种锁机制?MyISAM还是InnerDB?
好在我这个表无论那种方式的锁机制,由于没有索引,所以都是表级别的锁。而 我们涉及的操作无非查询,或者增删改。

通过应用对数据库操作的类型分为读锁和写锁 :

读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响 (读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求)

写锁(排它锁):当前写操作没有完成前,它会阻断其他写锁和读锁(则会阻塞其他用户对同一表的读和写操作)

重点当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。上面说的都是针对应用的操作,而不是mysql客户端,客户端任然是可以执行的。这些锁是应用级别上的。
上面这句就是导致我这个sql死锁的原因:我这个update语句是对全表扫描匹配,然后操作为更新。由于数据量大—将近95000条数据,这种95000条数据匹配95000条数据。相当于95000*95000这是多大的计算量?当这个sql拿到操作的锁后,后面的无论查询还是别的操作都别想了。所以报了个这样的错误:Lock wait timeout exceeeded.

知道原因,该如何解决?答案是杀掉这个进程!

  1. show processlist 来查看执行的这个sql对应的进程是哪个。执行的sql语句在info字段中。通过看执行时间Time即可知道,如果时间过长,就是导致死锁的原因。看到sql对应的进程id为73
    在这里插入图片描述
  2. kill 73 执行杀掉这个线程就行了。

解决完问题,剩下的就是如何优化sql了。优化首先着手点就是能不能控制下查表范围。这是最主要的。然后是加索引啥的。
下面是我sql优化后的效果,执行起来贼快:

UPDATE platform_front_category p1, 
(
SELECT 
	pfc1.id, pfc2.id as p2id,pfc2.parent_id as p2parentId 
FROM platform_front_category pfc1, platform_front_category pfc2 
where pfc1.platform_id = 20170410106 
and pfc2.platform_id = 20170410106
and pfc1.level=pfc2.level 
and pfc1.name=pfc2.name
and pfc1.category_status=1
and pfc2.category_status=2
and pfc1.sort_number=pfc2.sort_number
and pfc1.has_leaf=pfc2.has_leaf
and pfc1.is_quick=pfc2.is_quick
) p2 
SET p1.id_temp = p2.p2id ,p1.parent_id_temp = p2.p2parentId, p1.modified=now()
WHERE p1.platform_id = 20170410106 AND  p1.id = p2.id;

主要思路就是先先查询处子表,在去关联。而不是全表关联后在家条件筛选。

猜你喜欢

转载自blog.csdn.net/zhanglf02/article/details/86487214