一、MyISAM的锁机制(表锁)
在MyISAM中,当前会话查询一个表中的数据时,会将该表设置为读锁,当前会话可以查询表中的数据,但不能修改,也不能对其他表进行操作,需要提交后即可;其他会话也可以查询该表的数据,但不能修改该表的数据,但是可以对其他表进行操作。
在当前会话中,如果修改表中的数据,会将该表设置为写锁,当前会话可以查询表中的数据,也可以对表中的数据进行操作,但是不能对其他表进行操作,需要提交后即可;其他会话不能对该表进行查询的操作,如果进行了查询,处于阻塞状态,需要等待第一个会话提交后方可查询。(查询都需要阻塞,对表的修改就更不可能了。)
二、InnoDB的锁机制(行锁)
在InnoDB中,如果当前会话对表的数据进行操作,会将被操作的行数据进行加锁,加锁期间,当前会话不能对其他表进行操作,其他会话不能对加锁的行数据进行操作,如果进行了操作,处于阻塞状态,但是可以对未加锁的行数据进行操作。
1. 索引失效行锁表表锁:
例:
a是int型,b是varchar型。并且两个字段都有单独的索引。
第一个会话:
第二个会话:
当where中b的查询字段没有加单引号时,b的索引失效,但select语句依然能执行,结果依然正确。但第二个会话对表中的其他字段进行操作时,会出现阻塞状态即行锁变成了表锁。
2. 间隙锁:
什么是间隙锁:
当我们用范围条件而不是相等条件检索数据,InnoDB会给符合条件的数据记录的索引项加锁,对于键值在条件范围内但并不存在的记录,叫做“间隙”。
InnoDB也会对这个“间隙”加锁,这种锁机制就是间隙锁(Next-Key锁)。
例:
第一个会话:
第二个会话:
由于第一个会话的查询进行了范围的查询,就锁定了整个范围内的所有索引键值,即使这个键值不存在;第二个会话对该表中不存在的索引键值进行插值,并且第一个会话将其进行了间隙锁,所以第二个会话会处于阻塞状态。
3. 间隙锁的危害:
当锁定一个范围键值之后,即使某个不存在的键值也会被无辜的锁定,而造成了在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。
4. 如何锁定具体的某一行:
5. 通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况。
对于这五个状态,比较重要的是
尤其是当等待次数很高,而且每次等待时长也不小的时候,我们就需要分析系统中为什么会有如此多的等待,然后根据分析结果着手指定优化计划。
6. 优化建议:
(1)尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁。
(2)合理设计索引,尽量缩小锁的范围。
(3)尽可能较少检索条件,避免间隙锁。
(4)尽量控制事务大小,减少锁定资源量和时间长度。
(5)尽可能低级别事务隔离。
三、总结
InnoDB存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表锁会要更高一些,但是在整体并发处理能力方面要远远优于MyISAM的表级锁定的,当系统并发量较高的时候,InnoDB的整体性能和MyISAM相比就会有比较明显优势了。
但是,InnoDB的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让InnoDB的整体性能表现不仅不能让MyISAM高,甚至可能会更差。