Detailed MySQL auto-increment primary keys

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/qq_40378034/article/details/90736544

First, since the value stored in where?

Different engines for different retention policy from value-added

Since the value 1.MyISAM engine is stored in a data file

Since the value 2.InnoDB engine, in MySQL5.7 and earlier, since the value stored in memory, and no persistent. After each restart, when the table is first opened, will go from a maximum value of max (id), then max (id) + step as the current value from the table

select max(ai_col) from table_name for update;

MySQL8.0 value before the release, the self-value changes recorded in the redo log, the restart when the restart rely redo log recovery

Second, since the value modification mechanism

If the id field is defined as the AUTO_INCREMENT, insert a row in the time, since the value of the behavior is as follows:

1. id field is specified as 0, null value or if the specified data is inserted, then put the filling table to the current value of the self-energizing AUTO_INCREMENT field

2. If the data is inserted id field specifies the specific value, directly using the values ​​specified in the statement

Suppose, a secondary insert value of X, from the current value of Y

1. If X <Y, then the value from the table unchanged

2. If X> = Y, it is necessary to modify the current value from the new self-appreciation

The new self-value generation algorithm is: starting from auto_increment_offset (initial value), to auto_increment_increment (steps) of the step for superimposing, until the first value is greater than X, as the new value from

Third, since the value-added opportunity to modify

Create a table t, where id is auto-increment primary key field, c is the only index, construction of the table statement is as follows:

CREATE TABLE `t` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `c` (`c`)
) ENGINE=InnoDB;

Hypothesis, which has been table t (1,1,1) of this record, then insert data then execute a command:

insert into t values(null, 1, 1); 

The implementation process is as follows:

1. Run the engine interface calls InnoDB writes a line, passing the value of this line is (0,1,1)

2.InnoDB found not specified increment for the value of id, table acquired from the current value t 2

3. change the value of the incoming line (2,1,1)

4. The change from the value table 3

5. Continue insert data operation, since the recorded c = 1 already exists, it is reported Duplicate key error (unique key violations), statement returns

Corresponding to the flowchart is executed as follows:
Here Insert Picture Description
After that, insert a new row of data, id is incremented to get 3. Appeared in the case increment primary keys discontinuous

The only key violation and transaction rollback will result from increased primary key id discontinuity

Fourth, increase the self-locking optimization

Increment id lock is not a transaction lock, but finished each application immediately released to allow other transactions to apply

But in MySQL5.0 version of the time, the self-locking range is increased the statement level. That is, if a statement is filed for a table increment lock, the lock will wait until the statement released after the end of execution

MySQL5.1.22 version introduces a new strategy, new parameters innodb_autoinc_lock_mode, the default value is 1

1. This parameter is set to 0, indicating that the policy adopted MySQL5.0 previous version, that statement is executed after the end of the lock release

2. This parameter is set to 1

  • Ordinary insert statements increment lock is released immediately after application
  • This is similar to bulk insert ... select statement insert data, increase self-locking or to wait for the end of the sentence before being released

3. This parameter is set to 2, all applications increment primary key operation lock is released after application

For consistency of the data, the default is set to 1
Here Insert Picture Description
if sessionB applied immediately after release from value-added increment lock, then this may be the case:

  • sessionB first insert the two rows (1,1,1), (2,2,2)
  • sessionA obtained to apply the self-energizing id id = 3, the insert (3,5,5)
  • After, sessionB continues, insert two records (4,3,3), (5,4,4)

当binlog_format=statement的时候,两个session是同时执行插入数据命令的,所以binlog里面对表t2的更新日志只有两种情况:要么先记sessionA的,要么先记录sessionB的。无论是哪一种,这个binlog拿到从库执行,或者用来恢复临时实例,备库和临时实例里面,sessionB这个语句执行出来,生成的结果里面,id都是连续的。这时,这个库就发生了数据不一致

解决这个问题的思路:

1)让原库的批量插入数据语句,固定生成连续的id值。所以,自增锁直到语句执行结束才释放,就是为了达到这个目的

2)在binlog里面把插入数据的操作都如实记录进来,到备库执行的时候,不再依赖于自增主键去生成。也就是把innodb_autoinc_lock_mode设置为2,同时binlog_format设置为row

如果有批量插入数据(insert … select、replace … select和load data)的场景时,从并发插入数据性能的角度考虑,建议把innodb_autoinc_lock_mode设置为2,同时binlog_format设置为row,这样做既能并发性,又不会出现数据一致性的问题

对于批量插入数据的语句,MySQL有一个批量申请自增id的策略:

1.语句执行过程中,第一次申请自增id,会分配1个

2.1个用完以后,这个语句第二次申请自增id,会分配2个

3.2个用完以后,还是这个语句,第三次申请自增id,会分配4个

4.依次类推,同一个语句去申请自增id,每次申请到的自增id个数都是上一次的两倍

insert into t values(null, 1,1);
insert into t values(null, 2,2);
insert into t values(null, 3,3);
insert into t values(null, 4,4);
create table t2 like t;
insert into t2(c,d) select c,d from t;
insert into t2 values(null, 5,5);

insert … select,实际上往表t2中插入了4行数据。但是,这四行数据是分三次申请的自增id,第一次申请到了id=1,第二次被分配了id=2和id=3,第三次被分配到id=4到id=7

由于这条语句实际上只用上了4个id,所以id=5到id=7就被浪费掉了。之后,再执行insert into t2 values(null, 5,5),实际上插入了的数据就是(8,5,5)

This is the third consecutive increase id no primary key id appears reasons

Guess you like

Origin blog.csdn.net/qq_40378034/article/details/90736544