InnoDB中不一样SQL语句设置的锁

锁定读(locking read)、更新(UPDATE)或删除(DELETE)一般会在SQL语句处理过程当中扫描的每一个索引记录上设置记录锁。语句中是否存在排除行的WHERE条件并不重要。InnoDB不记得确切的WHERE条件,而只知道哪一个索引范围被扫描。这些锁一般是next-key锁,它还会阻止在记录以前插入“间隙”。然而,间隙锁(gap lock)能够被显式禁用,这会致使不使用next-key锁。数据库

若是在检索中使用了二级索引,而且要设置的索引记录锁是排它的,则InnoDB也会检索相应的汇集索引记录并在它们上设置锁。性能

执行SQL语句时,若是没有找到可用的索引,MySQL必须扫描整个表来处理该语句,这样的话表的每一行都会被锁定,从而阻塞其余用户对表的全部插入。所以,建立良好的索引很是重要,这样能够避免扫描许多没必要要的行。优化

InnoDB设置特定类型的锁,以下所示:spa

  • SELECT ... FROM 是一致读,读取数据库快照,除非将事务隔离级别设置为SERIALIZABLE,不然不设置锁。对于SERIALIZABLE级别,检索会在遇到的索引记录上设置共享的next-key锁。可是,对于使用惟一索引来搜索惟一行的语句,只须要一个索引记录锁。code

  • 对于 SELECT ... FOR UPDATE 或者 SELECT ... LOCK IN SHARE MODE ,对扫描的行加锁,并对不符合结果集中包含条件的行(例如,若是它们不知足WHERE子句中给出的条件)释放锁。orm

  • SELECT ... LOCK IN SHARE MODE 在全部遇到的索引记录上设置共享的next-key锁。可是,对于使用惟一索引来搜索惟一行的语句,只须要一个索引记录锁。blog

  • SELECT ... FOR UPDATE 在搜索遇到的每一个记录上设置排它的next-key锁。可是,对于使用惟一索引来搜索惟一行的语句,仅须要索引记录锁定。索引

  • UPDATE ... WHERE ... 在搜索遇到的每一个记录上设置排它的next-key锁。可是,对于使用惟一索引来搜索惟一行的语句,仅须要索引记录锁定。事务

  • DELETE FROM ... WHERE ... 在搜索遇到的每一个记录上设置排它的next-key锁。可是,对于使用惟一索引来搜索惟一行的语句,仅须要索引记录锁定。rem

  • INSERT 在插入的行上设置排他锁。该锁是索引记录锁,不是next-key锁(即没有间隙锁),而且不会阻止其余会话插入到插入行以前的间隙中。

举个例子,假设有一张表t1,结构以下:

CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;

再假设,有三个会话操做顺序以下:

Session 1:

START TRANSACTION; INSERT INTO t1 VALUES(1);

Session 2:

START TRANSACTION; INSERT INTO t1 VALUES(1);

Session 3:

START TRANSACTION; INSERT INTO t1 VALUES(1);

Session 1:

ROLLBACK;

首先Session1得到i=1这一行的排它锁,接下来Session2和Session3因为主键重复只能请求获取该行的共享锁,因为行上已经有排它锁,所以Session2和Session3请求的共享锁不能被当即授予。再接着,Session1回滚,行上的排它锁被释放,因而Session2和Session3在该行上都持有共享锁,此时,死锁发生了,因为对方持有的共享锁,任何一方都不能得到该行的排它锁。

下面这组操做也是相似:

Session 1:

START TRANSACTION; DELETE FROM t1 WHERE i = 1;

Session 2:

START TRANSACTION; INSERT INTO t1 VALUES(1);

Session 3:

START TRANSACTION; INSERT INTO t1 VALUES(1);

Session 1:

COMMIT;

和前面的状况相似,Session1提交之后,Session2和Session3请求该行上的共享锁被当即授予,此时它们再请求获取排它锁时就出现死锁了,由于共享锁被另外一个事务持有。

补充: 汇集索引与辅助索引

clustered index (译:汇集索引、聚簇索引)

secondary index (译:二级索引、辅助索引)

每一个InnoDB表都有一个特殊的索引,称为汇集索引,用于存储行数据。一般,汇集索引与主键是同义词。为了从查询、插入和其余数据库操做中得到最佳性能,必须了解InnoDB如何使用汇集索引来优化每一个表的最多见的查找和DML操做。

Typically, the clustered index is synonymous with the primary key.

一般,“clustered index” 和 “primary key” 是一个意思。

  • 当你在表上定义一个PRIMARY KEY时,InnoDB将它用做汇集索引。为建立的每一个表定义一个主键。若是没有逻辑惟一的非空列或列集,请添加一个新的自动递增(auto-increment)列,其值将自动填充。

  • 若是你没有为你的表定义一个PRIMARY KEY,则MySQL会在全部键列都不为NULL的状况下找到第一个惟一索引,而且InnoDB使用它做为汇集索引。

  • 若是表没有主键或合适的惟一索引,InnoDB会在包含行ID值的合成列上内部生成一个名为GEN_CLUST_INDEX的隐藏汇集索引

经过汇集索引访问行很是快,由于索引搜索直接指向包含全部行数据的页。若是表很大,汇集索引体系结构一般节省磁盘I/O操做。

除了汇集索引以外的全部索引都称为二级索引。在InnoDB中,二级索引中的每条记录都包含该行的主键列,以及为二级索引指定的列。InnoDB使用此主键值在汇集索引中搜索行。

若是主键很长,则辅助索引将使用更多空间,所以具备主键较短是比较有利的。

With the exception of spatial indexes, InnoDB indexes are B-tree data structures. Index records are stored in the leaf pages of their B-tree or R-tree data structure. The default size of an index page is 16KB. Supported sizes are 64KB, 32KB, 16KB (default), 8KB, and 4KB.

相关文章
相关标签/搜索