mysql性能优化系列3-锁和事务

1. 锁分类

  • 表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发度最低。适合于以查询为主,只有少量按索引条件更新数据的应用。
  • 行级锁:开销大,加锁慢,会出现死锁。锁定粒度最小,发生锁冲突的概率最低,并发度也最高。适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用。
  • 页面锁:开销和加锁时间界于表锁和行锁之间,会出现死锁。锁定粒度界于表锁和行锁之间,并发度一般。

MyISAM和MEMORY存储引擎采用的是表级锁,InnoDB存储引擎既支持行级锁(默认)和表级锁。

2. MyISAM锁

MyISAM的表级锁有两种模式,共享锁和独写锁。

  • MyISAM表的读操作,不会阻塞其他会话对同一表的读请求,但会阻塞对同一表的写请求
  • MyISAM表的写操作,则会阻塞其他会话对同一表的读和写操作,当前会话可以对本表做CRUD
  • 一个会话使用LOCK TABLE命令给表加了读锁,这个会话可以查询锁定表中的记录,但更新或访问其他表都会提示错误

(1)隐式加锁
MyISAM在执行SELECT操作前,会自动给涉及的所有表加读锁,在执行UPDATE、DELETE、INSERT等操作前,会自动给涉及的表加写锁。
(2)显式加锁

  • 读锁:LOCK TABLE 表名 read
  • 写锁:LOCK TABLE 表名 write
  • 释放锁:unlock tables

concurrent_insert
MyISAM是读写互相阻塞,但不是完全串行化,也可以并行。concurrent_insert就是用来控制并发插入的

  • concurrent_insert=2,无论MyISAM表中有没有空洞(表的中间没有被删除的行),都允许在表尾并发插入记录
  • concurrent_insert=1(默认),如果MyISAM表中没有空洞,MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录
  • concurrent_insert=0,不允许并发插入

读写优先级
写进程先获得锁,即使读请求先到锁等待队列,写请求后到,写锁也会先获得锁。因此大量的更新操作会造成查询操作很难获得读锁,从而可能永远堵塞。解决方法: set low_priority_updates =1;,使该连接发出的更新请求优先级降低

3. InnoDB锁

3.1 行锁和表锁

(1)行锁
行锁分为共享锁和排它锁。

  • 共享锁:读锁。当一个事务对某几行上读锁时,允许其他事务对这几行进行读操作,但不允许其进行写操作
  • 排它锁:写锁。当一个事务对某几个上写锁时,不允许其他事务读写

(2)表锁
意向锁是一种表级锁。分为意向共享锁(IS)和意向排他锁(IX)。在给表加行锁前会先加表锁。

  • 意向共享锁(IS):事务给数据行加入共享锁前必须给该表的加IS锁。
  • 意向排他锁(IX):事务给数据行加入排他锁前必须给该表的加IX锁。
    mysql性能优化系列3-锁和事务_第1张图片
    注意
  • 各意向锁之间不冲突
  • 对于insert、update、delete,InnoDB会自动给涉及的数据加排他锁,select不会加任何锁
  • 显式加锁:SELECT … LOCK IN SHARE MODE(共享锁)、SELECT … FOR UPDATE(排他锁)
  • 意向锁是InnoDB自动加的,不需要用户干预
  • 行锁必须有索引才能实现,否则会自动锁全表,那么就不是行锁了
  • 上述共享锁和排他锁在事务中才有效果,普通的select查询不会加锁,所以一个会话即使加了排它锁、另一个会话使用普通select也可以查询

4. ACID

事务具有4个属性:原子性、一致性、隔离性、持久性。

  • 原子性(atomicity):事务是一个不可分割的工作单位,事务中所有操作要么全部成功,要么都不成功
  • 一致性(consistency):事务必须使数据库从一个一致性状态变到另一个一致性状态,不能有中间态
  • 隔离性(isolation):一个事务的执行不被其他事务干扰
  • 持久性(durability):事务一旦提交,对数据库的改变就是永久性的

5. 隔离性

隔离性(isolation):事务对数据库修改,在未提交完成前对于其他事务不可见。
隔离性分为四种:
(1)未提交读(READ UNCOMMITED)
有脏读现象,事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
(2)已提交读(READ COMMITED)
没有脏读,但不可重复读。事务A在读取同一数据后,事务B对数据作了更新并提交,然后事务A再次读取数据,这样事务A读取两次数据,但结果不一致
(3)可重复读(REPEATABLE READ)
不会有脏读、不可重复读。但会有幻读,一个事务读取到了另外一个事务insert的数据。
不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
(4)可串行化(SERIALIZABLE)
可避免脏读、不可重复读、幻读
隔离级别从未提交读->已提交读->可重复读->可串行化,由低到高,级别越高,执行效率越低
事务隔离级别为可重复读时,如果以索引列为条件更新数据,会存在间隙锁间、行锁、页锁的问题,从而锁住一些行。如果没有索引,更新数据时会锁住整张表。事务隔离级别为串行化时,读写数据都会锁住整张表。

你可能感兴趣的:(mysql)