A simple update statement, MySQL is how locked?

A look at the following sql statement:

# table T (id int, name varchar(20))
delete from T where id = 10;

MySQL in the process of implementation, how is it locked?

Look at the following statement:

select * from T where id = 10;

That this statement do? In fact, it contains too many knowledge points. To answer these two questions, you first need to know a little.

Knowledge Introduction

Multi-version concurrency control

In the MySQL default storage engine InnoDB, the implementation is based on multi-version concurrency control protocol --MVCC (Multi-Version Concurrency Control) ( Note: the MVVC relative, is based concurrency control locks, Lock-Based Concurrency Control). One of the biggest benefits of MVCC is: read is not locked, read and write do not conflict. In reading, more writing and less OLTP applications, read and write conflict is not very important, greatly improving the system of concurrent performance, at this stage, almost all RDBMS, support MVCC. In fact, MVCC will sentence summary: the same data temporarily save multiple versions of a way, thus achieving concurrency control.

A snapshot of the current read and read

In MVCC concurrency control, the read operation can be divided into two categories: a snapshot of the current read and read.

Snapshot read (simple select operation): reading is visible version of the record (may be historical versions), do not lock. That you do not know the answer to the second question it.

Current reading (special operation select, insert, delete and update): reading is recorded in the latest version, and the current reading will add records returned lock, thus ensuring that other matters will not be concurrent modification of this record.

Clustered index

Also called clustered index. In InnoDB, the data is organized clustered index: complete record stored in the primary key index, the primary key index, to get all the columns in a record.

The most left-prefix principles

That is, the left-most priority for this principle is a combination of indexes and index prefixes, understand:

1, in MySQL, conditional filtering, in accordance with the right until it encounters a matching range queries (>, <, between, like) is stopped matching, for example, a = 1 and b = 2 and c> 3 and d = 4 If the index (a, b, c, d) sequence, d is less than the index, if the establishment of (a, b, d, c) will spend on the index, the order in which a, b, d can be be adjusted.

2, and = can be scrambled in, for example a = 1 and b = 2 and c = 3 to establish (a, b, c) in any order index, MySQL query optimizer optimizes index recognizable form.

Two-phase locking

A traditional RDMS locked principle is 2PL (Two-Phase Locking, two-phase locking). That lock operation is divided into two phases: phase locking and unlocking phase, and ensure that lock and unlock stage stage do not want to pay. That in a transaction, no matter how many additions and deletions, are locked in locked stage, after the commit, into the unlocked stage, will unlock all.

Isolation Levels

MySQL / InnoDB, the definition of the four isolation levels:

Uncommitted the Read : read uncommitted records. This isolation level will not be used.

Committed the Read (RC) : for the current reading, RC isolation level to ensure that the reading of the record lock (lock records), there is a phantom read phenomenon.

The Read Repeatable (the RR) : for the current reading, RR isolation level of locking to ensure that the read record (record locking), while maintaining the scope of the read lock, the new record does not satisfy the query can be inserted (gap lock ), phantom read phenomenon does not exist.

The Serializable : From MVCC concurrency control degradation based concurrency control lock. It does not distinguish between current snapshot read and read and read all the operations are currently reading, plus read read locks (S locks), write write-lock (X lock). In this isolation level, read and write conflicts, so the performance of concurrent sharp decline in MySQL / InnoDB is not recommended.

 Gap and Next-Key Lock Lock

In complete InnoDB row lock consists of three parts:

Record Lock (Record Lock): Record locks a record in the index.

Lock gap (Gap Lock): a gap or lock to lock the index record intermediate value, or a first lock value or index record in front of the index after the last recorded value.

Next-Key Lock: the index of the combination lock on the recording and the recording gap lock before recording when the Next-Key lock.

For analysis

Complete understanding of little more than knowledge, we begin to analyze the first question. When you see this question, you probably will not hesitate to say, plus a write lock ah. The answer is also wrong also, because too little known conditions. Then there are those who need it known preconditions?

  • A premise: id column is not the primary key?
  • Premise: The current system of isolation level what is?
  • Premise three: id primary key column if not, then there is no index on the id column of it?
  • Four premise: id column if there are secondary index, it is the only index it?
  • Premise Five: What SQL execution plan? Index scan? Or full table scan

According to the above premise, there may be nine kinds in combination, of course, it is not completely enumerated.

  1. id column is the primary key, RC isolation level
  2. id is the second column unique index, RC isolation level
  3. id is the second column is not the only index, RC isolation level
  4. There is no index, RC isolation level on the id column
  5. d is the primary key column, RR isolation level
  6. id column is two unique index, RR isolation level
  7. id column is not unique index two, RR isolation level
  8. There is no index, RR isolation level on the id column

 A combination of: id + RC primary key

This combination is the simplest analysis, the time to execute the statement just to record the primary key id = 10 plus X lock. As shown below:

A simple update statement, MySQL is how locked?

Conclusion : id is the primary key is that this SQL statement only needs to lock id = X plus 10 on this record.

Combination 2: id unique index + RC

This combination, id is not the primary key, but a secondary Unique index key. In RC isolation level, how is it locked? Look:

A simple update statement, MySQL is how locked?

Since the index id is Unique, and therefore will choose to take the index delete statement id column's filter condition where, after the id = 10 record is found, the record will first Unique id = 10 on the index plus the X lock, at the same time, will according to the read name of the column back to the primary key index (clustered index), and the name on the clustered index = 'e' key corresponding to the primary key index plus X lock.

结论:若id列是Unique列,其上有Unique索引,那么SQL需要加两个X锁,一个对应于id Unique索引上的id = 10的记录,另一把锁对应于聚簇索引上的(name = 'e', id = 10)的记录。

 组合三:id不唯一索引+RC

该组合中,id列不在唯一,而是个普通索引,那么当执行sql语句时,MySQL又是如何加锁呢?看下图:

A simple update statement, MySQL is how locked?

由上图可以看出,首先,id列索引上,满足id = 10查询的记录,均加上X锁。同时,这些记录对应的主键索引上的记录也加上X锁。与组合er的唯一区别,组合二最多只有一个满足条件的记录,而在组合三中会将所有满足条件的记录全部加上锁。

结论:若id列上有非唯一索引,那么对应的所有满足SQL查询条件的记录,都会加上锁。同时,这些记录在主键索引上也会加上锁。

组合四:id无索引+RC

相对于前面的组合,该组合相对特殊,因为id列上无索引,所以在 where id = 10 这个查询条件下,没法通过索引来过滤,因此只能全表扫描做过滤。对于该组合,MySQL又会进行怎样的加锁呢?看下图:

A simple update statement, MySQL is how locked?

由于id列上无索引,因此只能走聚簇索引,进行全表扫描。由图可以看出满足条件的记录只有两条,但是,聚簇索引上的记录都会加上X锁。但在实际操作中,MySQL进行了改进,在进行过滤条件时,发现不满足条件后,会调用 unlock_row 方法,把不满足条件的记录放锁(违背了2PL原则)。这样做,保证了最后满足条件的记录加上锁,但是每条记录的加锁操作是不能省略的。

结论:若id列上没有索引,MySQL会走聚簇索引进行全表扫描过滤。由于是在MySQl Server层面进行的。因此每条记录无论是否满足条件,都会加上X锁,但是,为了效率考虑,MySQL在这方面进行了改进,在扫描过程中,若记录不满足过滤条件,会进行解锁操作。同时优化违背了2PL原则。

组合五:id主键+RR

该组合为id是主键,Repeatable Read隔离级别,针对于上述的SQL语句,加锁过程和组合一(id主键+RC)一致。

组合六:id唯一索引+RR

该组合与组合二的加锁过程一致。

组合七:id不唯一索引+RR

在组合一到组合四中,隔离级别是Read Committed下,会出现幻读情况,但是在该组合Repeatable Read级别下,不会出现幻读情况,这是怎么回事呢?而MySQL又是如何给上述语句加锁呢?看下图:

A simple update statement, MySQL is how locked?

该组合和组合三看起来很相似,但差别很大,在改组合中加入了一个间隙锁(Gap锁)。这个Gap锁就是相对于RC级别下,RR级别下不会出现幻读情况的关键。实质上,Gap锁不是针对于记录本身的,而是记录之间的Gap。所谓幻读,就是同一事务下,连续进行多次当前读,且读取一个范围内的记录(包括直接查询所有记录结果或者做聚合统计), 发现结果不一致(标准档案一般指记录增多, 记录的减少应该也算是幻读)。

那么该如何解决这个问题呢?如何保证多次当前读返回一致的记录,那么就需要在多个当前读之间,其他事务不会插入新的满足条件的记录并提交。为了实现该结果,Gap锁就应运而生。

如图所示,有些位置可以插入新的满足条件的记录,考虑到B+树的有序性,满足条件的记录一定是具有连续性的。因此会在 [4, b], [10, c], [10, d], [20, e] 之间加上Gap锁。

Insert操作时,如insert(10, aa),首先定位到 [4, b], [10, c]间,然后插入在插入之前,会检查该Gap是否加锁了,如果被锁上了,则Insert不能加入记录。因此通过第一次当前读,会把满足条件的记录加上X锁,还会加上三把Gap锁,将可能插入满足条件记录的3个Gap锁上,保证后续的Insert不能插入新的满足 id = 10 的记录,也就解决了幻读问题。

而在组合五,组合六中,同样是RR级别,但是不用加上Gap锁,在组合五中id是主键,组合六中id是Unique键,都能保证唯一性。一个等值查询,最多只能返回一条满足条件的记录,而且新的相同取值的记录是无法插入的。

结论:在RR隔离级别下,id列上有非唯一索引,对于上述的SQL语句;首先,通过id索引定位到第一条满足条件的记录,给记录加上X锁,并且给Gap加上Gap锁,然后在主键聚簇索引上满足相同条件的记录加上X锁,然后返回;之后读取下一条记录重复进行。直至第一条出现不满足条件的记录,此时,不需要给记录加上X锁,但是需要给Gap加上Gap锁吗,最后返回结果。

组合八:id无索引+RR

该组合中,id列上无索引,只能进行全表扫描,那么该如何加锁,看下图:

A simple update statement, MySQL is how locked?

如图,可以看出这是一个很恐怖的事情,全表每条记录要加X锁,每个Gap加上Gap锁,如果表上存在大量数据时,又是什么情景呢?这种情况下,这个表,除了不加锁的快照读,其他任何加锁的并发SQL,均不能执行,不能更新,删除,插入,这样,全表锁死。

Of course, and as a combination of four, MySQL has been optimized, is semi-consistent read. The case of semi-consistent read on, for recording conditions are not satisfied, MySQL will advance its lock, the lock will be released at the same time Gap. The semi-consistent read is how to trigger: either in the Read Committed isolation level; either in the Repeatable Read isolation level, set innodb_locks_unsafe_for_binlog parameters.

Conclusion : In the Repeatable Read isolation level, if a full table scan of the current reading, it will lock all the records on the table, and add all of Gap Gap locks, put an end to all the delete / update / insert operation. Of course, in MySQL, you can trigger the semi-consistent read to alleviate the impact of concurrent locking overhead, but the semi-consistent read itself will bring other problems, it is not recommended.

A combination of nine: Serializable

In the final combination, for an appeal to remove SQL statements, locking procedure and the same combination of eight. However, for the query (such as select * from T1 where id = 10 ) , in under RC, RR isolation levels, snapshots are read, unlocked. In Serializable isolation level, whether the query will be locked, that is a snapshot reading does not exist, MVCC downgraded Lock-Based CC.

Conclusion: In MySQL / InnoDB, the so-called reading is not locked, do not apply to all cases, but isolation levels and relevant. In Serializable isolation level, all operations will be locked.

A simple delete statement will lock case analysis is complete, but the learning does not stop there, continue for complex SQL statements and how to lock it? Analysis of the index in MySQL and how is it? Performance analysis, performance optimization which is how it? We need further study to explore

Guess you like

Origin blog.51cto.com/14230003/2457784