MyISAM支持表锁
InnoDB支持行级锁(row-level locking)也支持表级锁,但默认采用行级锁。
表锁和行锁的区别
表级锁:开销小,加锁快,不会出现死锁,锁定粒度大,发生所冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢,会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
表锁更适合于以查询为主,只有少量按索引条件更新数据的应用。
行级锁更适合于大量按索引条件并发更新少量不同数据,同时又有并发查询的应用。
MyISAM的两种锁模式
读锁和写锁(全称表共享读锁和表独占写锁)。
读锁
当前读锁时,允许读请求,但是会阻塞写请求。
写锁
当前写锁时,不能读也不能写。(当一个线程获得一个表的写锁后,只有持有锁的线程可以对表进行更新操作。其他线程的读写都会等待。)
如何加锁?
MyISAM在执行查询语句前,会自动给涉及的所有表加读锁,在执行更新操作前,会自动给涉及的表加写锁。
因此用户一般不用lock table test write;这样显式加锁。
给MyISAM表显式加锁,一般是为了模拟事务操作,实现对某一个时间点,多个表的一致性读取。
加锁时的并发请求处理
给表加读锁时加上local,可以允许在读取的时候进行尾部并发插入。
lock table test read local;
如果查询时用了别名,那么加锁是也要把别名带上。
local table test as a read local;
这个并发插入是MyISAM的一个系统变量Concurrent Inserts.当值为1或者2的的时候允许插入。(值为1时要求表中间没有被删除的行)
local只是允许了并发时的末尾插入,但是其他操作还是不行的。
MyISAM的锁调度
MyISAM的读锁和写锁时互斥的,读写操作是串行的。
当读锁请求和写锁请求并发时,或者读锁先一步进入锁队列,系统还是会优先写请求,因为一般认为写请求比较重要。这也是MyISAM不适合大量更新操作的应用原因 。因为大量更新的系统很难获得读锁,从而可能永远阻塞请求。
那么如何解决锁调度导致的阻塞问题呢?
可以通过执行命令set low_priority_updates=1使该连接发出的更新请求优先级降低。
或者启动时加上low-priority-updates参数,使MyISAM引擎默认给与读请求优先的权利。
扩展:一些需要长时间运行的查询操作,会使进程饿死,所以复杂查询应该空闲时间执行,一般情况应使用简单的查询或者中间表来解决。
网友评论