文章目录

    • 一、mysql数据结构
    • 二、mysql 三层架构
    • 三、聚集索引和非聚集索引
    • 四、为什么使用索引可以提高查询效率
    • 五、mysql索引失效的场景
    • 六、什么是回表
    • 七、什么是覆盖索引
    • 八、mysql应该基于什么条件来创建索引
    • 九、change buffer
    • 十、mysql性能监控
    • 十一、索引(条件)下推-ICP(index condition pushdown)
    • 十二、MRR(Multi-Range Read Optimization)
    • 十三、索引的优点
    • 十四、如何创建高效的索引
    • 十五、常见的索引失效的场景
    • 十六、mysql执行计划-type类型(const>eq_ref>ref>range>index>all)
    • 十七、MVCC(Mutil Version Concurrency Control 多版本并发控制)
    • 十八、事务隔离级别
    • 十九、ACID是通过什么实现的
    • 二十、mysql日志
    • 二十一、页合并、页分裂
    • 二十二、mysql锁
      • 1. 表级锁
      • 2. 行锁
      • 3. 共享锁(Share Lock)
      • 4. 排它锁(eXclusive Lock)
      • 5. 意向锁
      • 6. 记录锁(Record Locks)
      • 7. 间隙锁(Gap Locks)
      • 8. 临键锁(Next-key Locks)
      • 9. 自增锁

一、mysql数据结构

mysql使用b+tree为底层数据结构,至于为什么使用b+tree而不使用b-tree和红黑树,我们来分析一下。

红黑树:

红黑树存储的数据量大的时候,红黑树的节点层数多,也就是树的高度比较高,查找的底层数据时,查找次数就比较多,即对磁盘IO使用比较频繁,还有就是树的每个节点,存放的数据很少,通过计算本来树的每一层大概需要分配16KB的数据。而红黑树所存的数据远远小于16KB,造成空间的浪费

总结一下就是有两个缺点

  1. 浪费存储空间
  2. 磁盘读取太频繁(我们知道磁盘读取是很慢的,所以要想提高查询效率,就必须要尽可能的减少磁盘IO。)

那么我们可以从以下两点出发进行改进:

  1. 增加树每层的节点数量,这样可以对分配的16KB充分利用,即解决上面的读取浪费的问题
  2. 尽可能的让树的高度减小,使得树显得比较“矮胖”,这样可以减少读取磁盘的次数

那么怎么样才可以实现以上的方法呢?这就需要用到b-tree了。

B-Tree:

一棵m阶的B-Tree有如下特性:

  1. 每个节点最多有m个孩子。
  2. 除了根节点和叶子节点外,其它每个节点至少有Ceil(m/2)个孩子。
  3. 若根节点不是叶子节点,则至少有2个孩子
  4. 所有叶子节点都在同一层,且不包含其它关键字信息
  5. 每个非终端节点包含n个关键字信息(P0,P1,…Pn, k1,…kn)
  6. 关键字的个数n满足:ceil(m/2)-1 <= n <= m-1
  7. ki(i=1,…n)为关键字,且关键字升序排序。
  8. Pi(i=1,…n)为指向子树根节点的指针。P(i-1)指向的子树的所有节点关键字均小于ki,但都大于k(i-1)

当看完上面的特性我是崩溃的,这也太多太复杂了,所以放张图来理解一下。

B-Tree
每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。

模拟查找关键字29的过程:

  1. 根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】

  2. 比较关键字29在区间(17,35),找到磁盘块1的指针P2。

  3. 根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】

  4. 比较关键字29在区间(26,30),找到磁盘块3的指针P2。

  5. 根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】

  6. 在磁盘块8中的关键字列表中找到关键字29。

分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素。B-Tree相对于红黑树缩减了节点个数,使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。

可以看到B-Tree完美解决了这两个问题,在每个节点都有data数据,且根据特性来维持树的高度。但是每一个页的存储空间是有限的,如果data数据较大会导致每个节点能存储的key数量很小,当数据量很大的时候,同样会导致树的高度增加,从而增加磁盘IO次数,影响查询效率,这是我们不愿意看到的。

B+Tree:

B+Tree是在B-Tree基础上的一种优化,使其更适合实现存储索引结构,InnoDB存储引擎就是用B+Tree实现其索引结构。
在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。

B+Tree相对于B-Tree有几点不同:

  1. 非叶子节点只存储键值信息。
  2. 所有叶子节点之间都有一个链指针。
  3. 数据记录都存放在叶子节点中。

由于B+Tree的非叶子节点只存储键值信息,假设每个磁盘块能存储4个键值及指针信息,则变成B+Tree后其结构如下图所示:

B+Tree
通常在B+Tree上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。因此可以对B+Tree进行两种查找运算:一种是对于主键的范围查找和分页查找,另一种是从根节点开始,进行随机查找。
我们可以看到,通过这种巧妙的设计,既减少了树的高度,还存储了更多的数据。

B+Tree 索引为什么可以支持千万级别数据量的查找
分析:
MySQL 官方对非叶子节点(如最上层 h = 1的节点,B+Tree高度为3) 的大小是有限制的,通过执行
SHOW GLOBAL STATUS like 'InnoDB_page_size'
可以得到大小为 16384,即 16k大小。
那么第二层也是16k大小。

假如:B+Tree的表都存满了。索引的节点的类型为BigInt,大小为8B,指针为6B。
最后一层,假如 存放的数据data为1k 大小,那么

  1. 第一层最大节点数为: 16k / (8B + 6B) = 1170 (个);
  2. 第二层最大节点数也应为:1170个;
  3. 第三层最大节点数为:16k / 1k = 16 (个)。

则,一张B+Tree的表最多存放 1170 * 1170 * 16 ≈ 2千万。
所以,通过分析,我们可以得出,B+Tree结构的表可以容纳千万数据量的查询。

二、mysql 三层架构

  • 客户端(client层)

  • 服务端(server层)

    • 连接器(管理连接和一些权限验证)

    • 分析器(语法分析、词法分析;验证sql语句是否正确。)

    • 优化器(优化sql语句,规定执行流程;优化后会形成执行计划)

    • 执行器(取到由优化器制作好的执行计划,跟存储引擎层进行交互)

  • 存储引擎(引擎层)

    • innodb:磁盘

    • myisam:磁盘

    • memory:内存

三、聚集索引和非聚集索引

  • 聚集索引:数据和索引一起存放

    • 主键索引:所有数据都存放在叶子节点

    • 非主键索引:叶子节点只存放主键

  • 非聚集索引:数据和索引分开存放,从索引文件查找到数据后,会拿该数据再去数据文件中进行查找,叶子节点只存放索引列数据

四、为什么使用索引可以提高查询效率

  1. mysql有两个存储引擎,innodb和myisam,innodb使用的是聚集索引,聚集索引就是数据和索引存放在一起,以b+tree的数据结构存放

    • 主键索引:叶子节点存放主键数据和其他数据

    • 非主键索引:叶子节点只存放主键数据

    myisam使用的是非聚集索引,非聚集索引就是数据和索引分开存放,索引文件采用b+tree的数据结构存放,先从索引文件查找数据,再根据查找后的数据去数据文件进行查找,而且叶子节点只存放索引列数据

  2. 使用索引可以提高查询效率,全依赖于b+tree的这种数据结构,也就是通过这种数据结构,可以更快的查询到目标数据。

五、mysql索引失效的场景

  • where语句中包含or时,可能会导致索引失效,or的前后必须都是索引列

  • 使用负向查询,比如,not、!=、<>、!<、!>、not in、not like等

  • 使用内置函数的时候

  • 隐式类型转换的时候,比如user_id是varchar类型,但是sql里面是where user_id = 12,12是数字12没有加引号

  • 关联查询时,两个字段的编码不一致

  • 对索引列进行计算的时候

  • like查询以%开头时,会导致索引失效

  • 联合索引中,违背最左匹配原则,一定会导致索引失效

六、什么是回表

拿innodb举例,innodb有两大类索引,聚集索引和普通索引;聚集索引可以直接获取表数据,查询一遍即可,普通索引树的叶子结点存放的是主键ID,所以普通索引会先查询普通索引树,然后获取到主键ID,再去主键索引树查询一遍,这个过程,称之为回表。

七、什么是覆盖索引

意思就是只需要在一颗索引树上就能获取sql所需的所有列数据,无需回表,速度更快,通俗的说就是给需要查询的字段加上索引,通常使用联合索引。

八、mysql应该基于什么条件来创建索引

  • 在经常搜索的列上创建索引

  • 在经常被用在连接的列上创建索引

  • 在经常使用where子句的列上创建索引

  • 唯一性太差的列不适合单独创建索引,即使会频繁的作为查询条件

  • 更新非常频繁的字段不适合创建索引

九、change buffer

在mysql中数据分为内存和磁盘两个部分;在buffer pool(缓冲池)中缓存热点数据页和索引页,减少磁盘IO;通过changeBuffer就是为了缓解磁盘写的一种手段。

changeBuffer就是在“非唯一索引页”不在buffer pool中时,对页进行了写操作的情况下,先将记录变更缓冲,等未来数据被读取时,再将changeBuffer中的操作merge到原数据页的技术,在mysql5.5之前,叫插入缓冲(insert buffer),只针对insert做了优化;在之后的版本对delete和update也有效了,叫做写缓冲(change buffer)

将changeBuffer中的操作合并到数据页(持久化),得到最新结果的过程称之为merge(合并),以下情况会触发merge

  • 访问这个数据页

  • 后台master线程会定期merage

  • 数据库缓冲池(buffer pool)不够用时

  • 数据库正常关闭时

  • redolog写满时

changeBuffer为什么只针对“非唯一索引页”呢

  1. 唯一索引:

    所有的更新操作都要判断这个操作是否违反唯一性约束,这个操作就要把数据页读入内存才能判断;既然都已经读入内存了,那么直接更新内存会更快,根本没有必要使用change buffer。

  2. 普通索引:

    不需要判断唯一性,在“非唯一普通索引页”不在缓冲池(buffer pool)中,才使用change buffer。

十、mysql性能监控

  1. show profile(需要开启,set profiling=1;)(已经被弃用了,高版本会被废弃掉)

  2. performance schema替代show profile。

    默认是开启的,且5.5版本后才有
    用于监控mysql server在一个较低级别的运行过程中的资源消耗、资源等待等情况。

  3. show processlist:查询连接的线程个数,来观察是查看大量线程处于不正常的状态或者其他不正常的特征

    1. 数据库连接池:

      1. dbcp

      2. c3p0

      3. druid

      4. HiKariCP(spring boot默认推荐的数据库连接池,目前最快)

    2. id:session id

    3. user:操作的用户

    4. host:操作的主机

    5. db:数据库

    6. command:当前状态

      1. sleep:线程正在等待客户端发送新的请求

      2. query:线程正在执行查询或正在将结果发送给客户端

      3. locked:在mysql的服务层,该线程正在等待表锁

      4. analyzing and statistics:线程正在手机存储引擎的统计信息,并生成查询的执行计划

      5. copying to tmp table:线程正在执行查询,并且将其结果集都复制到一个临时表中

      6. starting result:线程正在对结果集进行排序

      7. sending data:线程可能在多个状态之间传送数据,或者在生成结果集或者向客户端返回数据

  4. info:详细的sql语句

  5. time:相应命令执行时间

  6. state:命令执行状态

十一、索引(条件)下推-ICP(index condition pushdown)

  • 索引下推(index condition pushdown )简称ICP,在Mysql5.6的版本上推出,用于优化查询。

  • 在不使用ICP的情况下,在使用非主键索引(又叫普通索引或者二级索引)进行查询时,存储引擎通过索引检索到数据,然后返回给MySQL服务器,服务器然后判断数据是否符合条件 。

  • 在使用ICP的情况下,如果存在某些被索引的列的判断条件时,MySQL服务器将这一部分判断条件传递给存储引擎,然后由存储引擎通过判断索引是否符合MySQL服务器传递的条件,只有当索引符合条件时才会将数据检索出来返回给MySQL服务器 。

  • 索引条件下推优化可以减少存储引擎查询基础表的次数,也可以减少MySQL服务器从存储引擎接收数据的次数。

  • 说白了,就是把本来应该server层做的判断交给了引擎层去做。

十二、MRR(Multi-Range Read Optimization)

  1. MRR技术是MySQL5.6版本开始引入的,当一个表很大并且没有缓存在buffer pool中时,由于二级索引和主键的排列顺序一般情况下是不一样的,在二级索引上使用范围扫描回表读取行数据时会导致产生大量的随机I/O,通过MRR优化,MySQL会通过索引扫描收集相关行数据的主键,将主键值的集合存储到read_rnd_buffer中,然后在buffer中对主键进行排序,最后利用排好序的主键再回表查询。同时,如果缓冲池不够大的话,频繁的离散读还会导致缓存中的页频繁的被替换出缓冲池,然后又不断的被读入缓冲池,若按照主键顺序进行访问的话,可以减少数据页的读取,降低数据页被频繁替换出入缓冲池的情况。

  2. 很明显,对于只返回一行数据的查询,是没有必要 MRR 的,而如果你把 mrr_cost_based 设为 off,那优化器就会通通使用 MRR,这在有些情况下是很 stupid 的,所以建议这个配置还是设为 on,毕竟优化器在绝大多数情况下都是正确的。另外还有一个配置 read_rnd_buffer_size ,是用来设置用于给 rowid 排序的内存的大小。

  3. 显然,MRR 在本质上是一种用空间换时间的算法。MySQL 不可能给你无限的内存来进行排序,如果 read_rnd_buffer 满了,就会先把满了的 rowid 排好序去磁盘读取,接着清空,然后再往里面继续放 rowid,直到 read_rnd_buffer 又达到 read_rnd_buffe 配置的上限,如此循环。

  4. MRR优化的目的就是为了减少磁盘的随机访问,并将随机I/O转化顺序I/O,降低查询过程中的I/O开销,同时减少缓冲池中数据页被替换的频次。

  5. 好处:

    1. 磁盘和磁头不再需要来回做机械运动;

    2. 可以充分利用磁盘预读,比如在客户端请求一页的数据时,可以把后面几页的数据也一起返回,放到数据缓冲池中,这样如果下次刚好需要下一页的数据,就不再需要到磁盘读取。这样做的理论依据是计算机科学中著名的局部性原理:“当一个数据被用到时,其附近的数据也通常会马上被使用。”

    3. 在一次查询中,每一页的数据只会从磁盘读取一次

    MySQL 从磁盘读取页的数据后,会把数据放到数据缓冲池,下次如果还用到这个页,就不需要去磁盘读取,直接从内存读。

    但是如果不排序,可能你在读取了第 1 页的数据后,会去读取第2、3、4页数据,接着你又要去读取第 1 页的数据,这时你发现第 1 页的数据,已经从缓存中被剔除了,于是又得再去磁盘读取第 1 页的数据。
    而转化为顺序读后,你会连续的使用第 1 页的数据,这时候按照 MySQL 的缓存剔除机制,这一页的缓存是不会失效的,直到你利用完这一页的数据,由于是顺序读,在这次查询的余下过程中,你确信不会再用到这一页的数据,可以和这一页数据说告辞了。

十三、索引的优点

  • 减少磁盘扫描,提高检索效率,避免了全表扫描。

  • 提高排序和分组的效率。

  • 将随机IO转化为顺序IO。

  • 提高部分聚合函数的效率,比如min(),max()等。

十四、如何创建高效的索引

  • 在经常用于排序和分组查询的字段上建立索引,可以避免了内存排序和随机I/O。

  • 在选择性较高的字段上建立索引,查看选择性公式select count(distinct a)/count(*) from t1,越接近1越好,一般超过33%就算是比较高效的索引了。

  • 如果没有强烈的业务需求,建议建立自增主键,这样的主键占用空间小,顺序写入,减少页分裂。

  • 利用较短的键值作为索引性能比较好,可能的话尽量使用整数类型。

  • 对于where条件中涉及多个字段时可以考虑建立联合索引,建议将选择性高的列放到 索引最左列,SQL查询时满足最左原则。

  • 对于select后面经常用到的字段可以考虑创建索引,查询时使用覆盖索引查询,避免回表。

  • 索引字段尽量设置为NOT NULL,NULL值会更加运算的复杂度。

  • 如果有 order by 的场景,尽量利用索引的有序性,避免出现using filesort 的情况,影响查询性能。

  • SQL投产前查看执行计划,SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,最好是 consts级别。

  • SQL语句中尽量避免使用左模糊或者全模糊查询,无法利用B+Tree 最左前缀匹配特性。

  • 考虑针对较长字符串型列使前缀索引,区分度可以使用 count(distinct left(列名, 索引长度))/count(*)来确定,请参看上一章的前缀索引部分。

  • 业务上具有唯一特性的字段,即使是组合字段,也建议建成唯一索引,数据库层面避免了脏数据的产生,对insert的影响可以忽略(阿里巴巴开发手册要求)。

  • 在表查询中,建议明确字段,不要使用 * 作为查询的字段列表。

  • 索引不宜过多,一般建议不超过6个,由于索引的创建和维护是有代价的,所以请不要创建不必要的索引。

十五、常见的索引失效的场景

  • 通过索引扫描的行数超过全表的20%-30%时,引擎会认为走全表扫描更有效。

  • 使用联合索引时没有遵循最左原则。

  • where后面出现 or 条件 ,且没有建立单列索引会导致失效。

  • 对索引使用了函数计算。

  • 统计信息不真实(严重不真实),导致执行计划错误。

  • 访问小表时,更倾向于全表扫描。

  • Where条件中对索引列使用左模糊或者全模糊查询。

十六、mysql执行计划-type类型(const>eq_ref>ref>range>index>all)

  • const:查询索引字段,并且表中最多只有一行匹配(好像只有主键查询只匹配一行才会是const,有些情况唯一索引匹配一行会是ref)

  • eq_ref:主键或者唯一索引

  • ref:非唯一索引(主键也是唯一索引)

  • range:索引的范围查询

  • index: (type=index extra = using index 代表索引覆盖,即不需要回表)

  • all:全表扫描(通常没有建索引的列)

十七、MVCC(Mutil Version Concurrency Control 多版本并发控制)

mvcc是为了实现快照读,也就是以乐观锁的形式进行读操作,通过版本链的方式,实现了读-写,写-读的并发执行,提升了系统的性能。

当前读:读取的是数据的最新版本(总是读取到最新的数据)

  • select … lock in share mode(共享锁)

  • select … for update(排它锁)

  • update

  • delete

  • insert

快照读:读取的是历史版本的记录

  • select …

事务隔离级别

  • 读未提交(READ UNCOMMITTED)

  • 读已提交(READ COMMITTED)

  • 可重复读(REPEATABLE READ)

  • 可串行化(SERIALIZABLE)

mvcc的实现原理主要依赖于记录中的三个隐藏字段以及undolog、read view来实现的。

隐藏字段:

每行记录除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID等字段。

  • DB_TRX_ID:6字节,最近修改的事务ID,记录创建这条记录或者最后一次修改该记录的事务ID

  • DB_ROLL_PTR:7字节,回滚指针,指向这条记录的上一个版本,用于配合undolog,指向上一个旧版本。

  • DB_ROW_ID:6字节, 隐藏主键,如果数据表没有主键,那么innodb会自动生成一个6字节的row_id。

undolog:

undolog 被称为回滚日志,表示在进行insert、delete、update操作的时候产生的方便回滚的日志。
当进行insert操作的时候,产生的undolog只在事务回滚的时候需要,并且在事务提交之后可以被立刻丢弃。

当进行update和delete操作的时候,产生的undolog不仅仅在事务回滚的时候需要,在快照读的时候也需要,所以不能随便删除,只有在快照读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除(当数据发生更新和删除操作的时候都只是设置一下老记录的deleted_bit,并不是真正的将过时的记录删除,因为为了节省磁盘空间,innodb有专门的purge线程来清除deleted_bit为true的记录,如果某个记录的deleted_bit为true,并且DB_TRX_ID相对于purge线程的read view 可见,那么这条记录一定是可以被清除的)

不同事务或者相同事务的对同一条记录的修改,会导致该记录的undolog生成一条记录版本线性表,即链表,undolog的链首就是最新的旧记录,链尾就是最早的旧记录。

Read View:

Read View是事务进行快照读操作的时候生成的读视图,在该事务执行快照读的那一刻,会生成一个数据系统当前的快照,记录并维护系统当前活跃事务的ID,事务的ID是递增的。

其实Read View的最大作用是用来做可见性判断的,也就是说当某个事务在执行快照读的时候,对该记录创建一个Read View的视图,把它当做条件去判断当前事务能够看到哪个版本的数据,有可能读取到的是最新的数据,也有可能读取的是当前行记录的undolog中某个版本的数据。

Read View遵循的可见性算法主要是将要被修改的数据的最新记录中的DB_TRX_ID(当前事务ID)取出来,与系统当前其他活跃事务的ID去对比,如果DB_TRX_ID跟Read View的属性做了比较,不符合可见性,那么就通过DB_ROLL_PTR回滚指针去取出undolog中的BD_TRX_ID做比较,即遍历链表中的DB_TRX_ID,直到找到满足条件的DB_TRX_ID,这个DB_TRX_ID所在的旧记录就是当前事务能看到的最新老版本数据。

Read View的可见性规则如下所示:

首先要知道Read View中的三个全局属性:
trx_list:一个数值列表,用来维护Read View生成时刻系统正活跃的事务ID
up_limit_id:记录trx_list列表中事务ID最小的ID
low_limit_id:Read View生成时刻系统尚未分配的下一个事务ID。

具体的比较规则如下:

  1. 首先比较DB_TRX_ID < up_limit_id,如果小于,则当前事务能看到DB_TRX_ID所在的记录,如果大于等于则进入下一个判断。
  2. 接下来判断DB_TRX_ID >= low_limit_id,如果大于等于则代表DB_TRX_ID所在的记录在Read View生成后才出现,那么对于当前事务肯定不可见,如果小于,则进入下一个判断。
  3. 判断DB_TRX_ID是否在活跃事务中,如果在,则代表在Read View生成时刻,这个事务还是活跃状态,还没有commit,修改的数据,当前事务也是看不到,如果不在,则说明这个事务在Read View生成之前就已经开始commit,那么修改的结果是能够看见的。

RC、RR级别下的innodb快照读有什么不同:
因为Read View生成的时机不同,从而造成RC、RR级别下的快照读的结果不同。

总结:在RC隔离级别下,是每个快照读都会生成并获取最新的Read View,而在RR隔离级别下,则是同一个事务中的第一个快照读才会创建Read View,之后的快照读获取的都是同一个Read View。

十八、事务隔离级别

READ UNCOMMITTED 读取未提交内容

在这个隔离级别,所有事务都可以"看到"未提交事务的执行结果。在这种级别上,可能会产生很多问题,除非用户真的知道自己在做什么,并有很好的理由选择这样做。本隔离级别很少用于实际应用,因为它的性能也不必其他性能好多少,而别的隔离级别还有其他更多的优点。读取未提交数据,也被称为"脏读"。

READ COMMITTED 读取已提交内容

大多数数据库系统的默认隔离级别(但是不是MySQL的默认隔离级别),满足了隔离的早先简单定义:一个事务开始时,只能“看见" 已经提交事务所做的改变,一个事务从开始到提交前,所做的任何数据改变都是不可见的,除非已经提交。这种隔离级别也支持所谓的"不可重复读"。这意味着用户运行同一个语句两次,看到的结果可能是不同的。

REPEATABLE READ 可重复读

MySQL数据库默认的隔离级别。该级别解决了READ UNCOMMITTED隔离级别导致的问题。它保证同一事务的多个实例在并发读取事务时,会“看到同样的“数据行。不过,这会导致另外一个棘手问题"幻读"。InnoDB和Falcon存储引擎通过多版本并发控制机制解决了幻读问题。

SERIALIZABLE 可串行化

该级别是最高级别的隔离级。它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简而言之,SERIALIZABLE是在每个读的数据行上加锁。在这个级别,可能导致大量的超时Timeout和锁竞争Lock Contention现象,实际应用中很少使用到这个级别,但如果用户的应用为了数据的稳定性,需要强制减少并发的话,也可以选择这种隔离级。

  • 脏读

    脏读是指一个事务读取了未提交事务执行过程中的数据。当一个事务的操作正在多次修改数据,而在事务还未提交的时候,另外一个并发事务来读取了数据,就会导致读取到的数据并非是最终持久化之后的数据,这个数据就是脏读的数据。

  • 不可重复读

    不可重复读是指对于数据库中的某个数据,一个事务执行过程中多次查询返回不同查询结果,这就是在事务执行过程中,数据被其他事务提交修改了。
    不可重复读同脏读的区别在于,脏读是一个事务读取了另一未完成的事务执行过程中的数据,而不可重复读是一个事务执行过程中,另一事务提交并修改了当前事务正在读取的数据。

  • 虚读(幻读)

    幻读是事务非独立执行时发生的一种现象,例如事务A批量对一个表中某一列列值为1的数据修改为2的变更,但是在这时,事务B对这张表插入了一条列值为1的数据,并完成提交。此时,如果事务A查看刚刚完成操作的数据,发现还有一条列值为1的数据没有进行修改,而这条数据其实是B刚刚提交插入的,这就是幻读。
    幻读和不可重复读都是读取了另一条已经提交的事务(这点同脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

十九、ACID是通过什么实现的

A:原子性(通过undolog保证原子性的实现)
C:一致性(是最终的追求,通过AID实现的)
I:隔离性(通过锁)
D:持久性(通过redolog保证持久性的实现)

二十、mysql日志

binlog:
归属于mysql server层,binlog 是逻辑日志,它记录的是操作语句涉及的每一行修改前后的值,在任何存储引擎下都可以使用。
二进制日志,用于主从复制、崩溃恢复,默认不开启。

undolog:
归属于innodb引擎,是Innodb MVCC的重要组成部分,主要用于记录历史版本数据,用于事务回滚。

redolog:
归属于innodb引擎,redolog 是物理日志,它记录的是数据页修改逻辑以及 change buffer 的变更,只能在innodb引擎下使用。

redolog 是搭配缓冲池、change buffer 使用的,缓冲池的作用是缓存磁盘上的数据页,减少磁盘的IO;change buffer 的作用是将写操作先存在内存中,等到下次需要读取这些操作涉及到的数据页时,就把数据页加载到缓冲池中,然后在缓冲池中更新;

事务的持久性是通过redolog实现的(write ahead log(WAL)),即先写日志再写数据;而因为binlog和redolog两种日志属于不同的组件,所以为了保证数据的一致性,要保证binlog和redolog的一致,所以有了二阶段提交的概念。

二阶段提交

详细执行流程:

  1. 执行器先从引擎中找到数据,如果在内存中则直接返回,如果不在内存中,查询后返回。
  2. 执行器拿到数据之后会先修改数据,然后调用引擎接口重新写入数据。
  3. 引擎将数据更新到内存,同时写数据到redolog中,此时处于prepare阶段,并通知执行器执行完成,随时可以操作。
  4. 执行器生成这个操作的binlog日志。
  5. 执行器调用引擎的事务提交接口,引擎把刚刚写完的redolog中的状态改成commit状态,更新完成。

如果不拆分成两个阶段提交:

  • 先写redolog,后写binlog: 假设在redolog写完,binlog还没有写完的时候,mysql进程异常重启。mysql可以把数据恢复回来,但是由于binlog还没写完就崩溃了,这时候binlog里面就没有记录这条数据。因此,之后备份日志的时候,存起来的binlog里面就没有这条语句,所以如果要用这个binlog来恢复临时库或者进行主从复制的时候,就会造成数据与原库不相等。

  • 先写binlog,后写redolog: 如果在binlog写完之后,mysql崩溃,由于redolog还没有写入,mysql重启后这个事务无效,所以这一条数据丢失,但是binlog里面已经记录了这一条数据,所以在之后用binlog进行恢复临时库或者主从复制的时候,就会造成数据与原库不相等。

预写日志 WAL(wite ahead log)

先写日志,再写数据

因为随机读写的效率要低于顺序读写,为了保证数据的一致性,可以先将数据通过顺序读写的方式写到日志文件中,然后再将数据写入到对应的磁盘文件中,这个过程顺序IO的效率要远远高于随机IO,换句话说,如果实际的数据没有写入到磁盘,那么只要日志文件保存成功了,数据就不会丢失,可以根据日志来进行数据的恢复。

二十一、页合并、页分裂

mysql底层的数据结构采用的B+tree,叶子节点中的每一页是由双向链表连接起来的,且顺序排列,一个页默认大小是16kb。

页的内部原理:

  • 页可以空或者填充满(100%),行记录会按照主键顺序来排列。例如在使用AUTO_INCREMENT时,你会有顺序的ID 1、2、3、4等。

  • 页还有另一个重要的属性:MERGE_THRESHOLD。该参数的默认值是50%页的大小,它在InnoDB的合并操作中扮演了很重要的角色

  • 当你插入数据时,如果数据(大小)能够放的进页中的话,那他们是按顺序将页填满的。若当前页满,则下一行记录会被插入下一页(NEXT)中。

  • 根据B+树的特性,它可以自顶向下遍历,但也可以在各叶子节点水平遍历。因为每个叶子节点都有着一个指向包含下一条(顺序)记录的页的指针。例如,页#5有指向页#6的指针,页#6有指向前一页(#5)的指针和后一页(#7)的指针。这种机制下可以做到快速的顺序扫描(如范围扫描)。

页合并:
当你删了一行记录时,实际上记录并没有被物理删除,记录被标记为删除并且它的空间变得允许被其他记录声明使用,当页中删除的记录达到MERGE_THRESHOLD(默认页体积的50%),InnoDB会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。

页分裂:
页可能填充至100%,在页填满了之后,下一页会继续接管新的记录。但如果存在这种情况呢,插入了一条新数据,新数据应该由页#10进行管理,但是页#10满了,而它的下一页,页#11也满了,数据也不可能不按顺序的插入,这个时候怎么办呢?由于每一页是由双向链表连接起来的

所以mysql的做法是(简化版):

  1. 创建新页
  2. 判断当前页(页#10)可以从哪里进行分裂(记录行层面)
  3. 移动记录行
  4. 重新定义页之间的关系

二十二、mysql锁

按照锁的粒度:

  • 表锁:意向锁、自增锁
  • 行锁:间隙锁、临键锁、记录锁

按照锁的方式:

  • 共享锁:读锁(S)

  • 排它锁:写锁(X)

  • 意向共享锁(IS)

  • 意向排它锁(I)

1. 表级锁

MySQL里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)。

  • 表锁

    表锁的语法是lock tables … read/write。可以用unlock tables主动释放锁,也可以在客户端断开的时候自动释放。lock tables语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。

    如果在某个线程A中执行lock tables t1 read,t2 wirte;这个语句,则其他线程写t1、读写t2的语句都会被阻塞。同时,线程A在执行unlock tables之前,也只能执行读t1、读写t2的操作。连写t1都不允许。

  • MDL(meta data lock)元数据锁

    另一类表级的锁是MDL。MDL不需要显式使用,在访问一个表的时候会被自动加上。MDL 不需要我们记命令,它是隐式使用的,访问表会自动加上。它的主要作用是防止 DDL(改表结构) 和 DML(CRUD 表数据) 并发的冲突。如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做了变更,删了一列,那么查询线程拿到的结果跟表结构对不上,肯定不行。

    在MySQL5.5版本引入了MDL,当对一个表做增删改查操作的时候,加MDL读锁;当要对表做结构变更操作的时候,加MDL写锁。

    • 读锁之间不互斥,因此可以有多个线程同时对一张表增删改查。
    • 读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。

给一个表加字段,或者修改字段,或者加索引,需要扫描全表的数据。在对大表操作的时候,需要特别小心,以免对线上服务造成影响。

图1

前提:注意,我这里的事务是手动开启和提交的。而 MDL 锁是语句开始时申请,事务提交才释放。所以,如果是自动提交就不会出现下面的问题。

session A先启动,这时候会对表t加一个MDL读锁。由于session B需要的也是MDL读锁,因此可以正常执行。之后sesession C会被blocked,是因为session A的MDL读锁还没有释放,而session C需要MDL写锁,因此只能被阻塞。如果只有session C自己被阻塞还没什么关系,但是之后所有要在表t上新申请MDL读锁的请求也会被session C阻塞。所有对表的增删改查操作都需要先申请MDL读锁,就都被锁住,等于这个表现在完全不可读写了。

事务中的MDL锁,在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放

  • 如何安全地给小表加字段?

    首先要解决长事务(一个事务包括 session A、B、C、D 的操作),事务不提交,就会一直占着MDL 锁。在MySQL的information_schema库的innodb_trx表中,可以查到当前执行的事务。如果要做DDL变更的表刚好有长事务在执行,要考虑先暂停DDL,或者kill掉这个长事务。

  • 如果要变更的表是一个热点表,虽然数据量不大,但是上面的请求很频繁,而又不得不加个字段,该怎么做?

    在alter table语句里面设定等待时间,如果在这个指定的等待时间里面能够拿到MDL写锁最好,拿不到也不要阻塞后面的业务语句,先放弃。之后再通过重试命令重复这个过程。

    // N 以秒为单位
    alter table tableName wait N add column .....
    

2. 行锁

mysql 的行索是在引擎实现的,但并不是所有引擎都支持行锁,不支持行锁的引擎只能使用表锁。行锁比较容易理解:行锁就是针对数据表中行记录的锁。比如:事务 A 先更新一行,同时事务 B 也要更新同一行,则必须等事务 A 的操作完成后才能进行更新。

  • 两阶段锁协议:

    先举个栗子:事务 A 和 B 对 student 中的记录进行操作。
    图2
    其中事务 A 先启动,在这个事务中更新两条数据;事务 B 后启动,更新 id = 1 的数据。由于 A 更新的也是 id = 1 的数据,所以事务 B 的 update 语句从事务 A 开始就会被阻塞,直到事务 A 执行 commit 之后,事务 B 才能继续执行。

    在事务期间,事务 A 实际上持有 id = 1 和 id = 2 这两行的行锁。如果事务 B 更新的是 id = 2 的数据,那么它阻塞的时间就是从 A 更新 id = 2 这行开始(事务 A 更新 id = 1 时,它并没有阻塞),到事务 A 提交结束,比更新 id = 1 数据阻塞的时间要短。 PS:理解这句话很重要。

    在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议,分为加锁阶段和解锁阶段,所有的 lock 操作都在 unlock 操作之后。
    根据这个特性,对于高并发的行记录的操作语句就可以尽可能的安排到最后面,以减少锁等待的时间,提高并发性能。

    假设你负责实现一个电影票在线交易业务,顾客 A 要在影院 B 购买电影票。我们简化一点,这个业务需要涉及到以下操作:

    1. 从用户 A 账户余额中扣除电影票价;
    2. 给影院 B 的账户余额增加这张电影票价;
    3. 记录一条交易日志。

    也就是说,要完成这个交易,需要 update 两条记录,并 insert 一条记录。当然,为了保证交易的原子性,我们要把这三个操作放在一个事务中。那么,怎样安排这三个语句在事务中的顺序呢? 分析一下:

    用户余额是个人的,并发很低;
    影院账户表每个用户都要访问,并发很高;
    交易记录是插入操作问题不大。

    这时将事务步骤安排成 3、1、2 这样的顺序是最佳的。因为此时如果有别的用户买票,它的事务在顺序 1、2 并不会阻塞,而是到了顺序 3 更新影院账户表才会引起阻塞。但它的阻塞时间是最短的,其他操作不需要等待锁。

  • 死锁:

    不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。举个行锁死锁的例子:两个事物相互等待对方持有的锁。
    图3
    操作开始:

    • 事务 A 持有 id = 1 的行锁,事务 B 持有 id = 2 的行锁;

    • 事务 A 想更新 id = 2 行数据,不料事务 B 已持有,事务 A 只能等待事务 B 释放 id = 2 的行锁;

    • 同理,事务 B 想更新 id = 1 行数据,不料事务 A 已持有,事务 B 只能等事务 A 释放 id = 1 的行锁。

    两者互相等待,这就是死锁。

  • 如何解决死锁?

    有两个解决策略:

    1. 进入等待,直到超时(加入等待时间

      首先是第一种:直接进入等待,直到超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 设置。 这个参数,默认设置的锁等待时间是 50s在 MySQL 中,像下面这样执行即可:

      // 设置等待时间
      mysql > set global innodb_lock_wait_timeout = 500;
      

      上面这个语句表示:当出现死锁以后,第一个被锁住的线程要过 500s 才会超时退出,然后其他线程才有可能继续执行。锁等待时间不能设置过小,有些线程可能并没有发生死锁,只是正常的等待锁。这就会造成本来正常的锁机制出问题,当然也不能太长。

    2. 进行死锁检测,主动回滚某个事务

      再看第二种:死锁检测,主动回滚某个事务。 MySQL 通过设置 innodb_deadlock_detect 的值决定是否开启检测,默认值是 on(开启)。

      主动死锁检测在发生死锁的时候,可以快速发现并进行处理的,但是它也有额外负担。
      什么负担呢?循环依赖检测,过程如下:

      新来的线程 F,被锁了后就要检查锁住 F 的线程(假设为 D)是否被锁,如果没有被锁,则没有死锁,如果被锁了,还要查看锁住线程 D 的是谁,如果是 F,那么肯定死锁了,如果不是 F(假设为 B),那么就要继续判断锁住线程 B 的是谁,一直走知道发现线程没有被锁(无死锁)或者被 F 锁住(死锁)才会终止

      如果大量并发修改同一行数据,死锁检测又会怎样呢?
      假设有 1000 个并发线程同时更新同一行,那么死锁检测操作就是 1000 x 1000 达到 100 万量级的。即便最终检测结果没有死锁,但这期间要消耗大量 CPU 资源。所以,就会出现 CPU 利用率很高,但是每秒却执行不了几个事务的情况。

    解决热点行更新问题:

    那前面两种方案都有弊端,死锁的问题应该怎么解决呢?
    一种比较依赖运气的方法就是:如果你能确保这个业务一定不会出现死锁,可以临时把死锁检测关掉。 但是这可能会影响到业务:开启死锁检测,出现死锁就回滚重试,不会影响到业务。如果关闭,可能就会大量超时,严重就会拖垮数据库。

    另一种就是在服务端(消息队列或者数据库服务端)控制并发度: 之所以担心死锁检测会造成额外的负担,是因为并发线程很多的时候,假设我们能在服务端做下限流,比如同一样最多只能允许 10 个线程同时修改。
    一个思想:减少死锁的主要方向,就是控制访问相同资源的并发事务量。

3. 共享锁(Share Lock)

共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到最新数据。Mysql会对查询结果中的每行都加共享锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请共享锁,否则会被阻塞。

用法:SELECT ... LOCK IN SHARE MODE;

  1. 多个事务的查询语句可以共用一把共享锁;
  2. 如果只有一个事务拿到了共享锁,则该事务可以对数据进行 UPDATE DETELE 等操作;
  3. 如果有多个事务拿到了共享锁,则所有事务都不能对数据进行 UPDATE DETELE 等操作。

使用场景:

  1. 确保某个事务查到最新的数据;
  2. 这个事务不需要对数据进行修改、删除等操作;
  3. 也不允许其它事务对数据进行修改、删除等操作;
  4. 其它事务也能确保查到最新的数据。

对于性能的影响:“虽然共享锁可以给多个事务共享,但一旦有多个事务同时拥有共享锁,则所有事务都不能对数据进行 UPDATE DETELE 等操作,也会导致其它事务的锁等待、锁等待超时、死锁等问题;

4. 排它锁(eXclusive Lock)

排他锁又称为写锁,简称X锁,顾名思义,排它锁不能与其它锁并存,而且只有一个事务能拿到某一数据行的排它锁,其余事务不能再获取该数据行的所有锁。Mysql会对查询结果中的每行都加排他锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请排他锁,否则会被阻塞。

用法:SELECT ... FOR UPDATE;

  1. 只有一个事务能获取该数据的排它锁;
  2. 一旦有一个事务获取了该数据的排它锁之后,其余事务对于该数据的操作将会被阻塞,直至锁释放。

使用场景:

  1. 确保某个事务查到最新的数据;
  2. 并且只有该事务能对数据进行修改、删除等操作。

对于性能的影响: 因为排它锁只允许一个事务获取,所以如果是业务繁忙的情况下,一旦有某个业务不能及时的释放锁,则会导致其它事务的锁等待、锁等待超时、死锁等问题;

5. 意向锁

意向锁意向锁是一种不与行级锁冲突的表级锁,其设计目的主要是为了在一个事务中揭示下一行将要被请求锁的类型。

InnoDB中的两个表锁:

  • 意向共享锁(IS):表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁

  • 意向排他锁(IX):类似上面,表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁。

用户无法操作意向锁,意向锁是由InnoDB自己维护的。说白了,意向锁是帮助InnoDB提高效率的一种手段。

对于insert、update、delete,InnoDB会自动给涉及的数据加排他锁(X);对于一般的select语句,InnoDB不会加任何锁,事务可以通过以下语句加共享锁或排他锁。

  • 共享锁:SELECT … LOCK IN SHARE MODE;

  • 排他锁:SELECT … FOR UPDATE;

意向锁解决了什么问题?

假设,事务A获取了某一行的排它锁,尚未提交,此时事务B想要获取表锁时,必须要确认表的每一行都不存在排他锁,很明显效率会很低,引入意向锁之后,效率就会大为改善:

  1. 如果事务A获取了某一行的排它锁,实际此表存在两种锁,表中某一行的排他锁和表上的意向排他锁。
  2. 如果事务B试图在该表级别上加锁时,则受到上一个意向锁的阻塞,它在锁定该表前不必检查各个页或行锁,而只需检查表上的意向锁。

打个比方,就像有个游乐场,很多小朋友进去玩,看门大爷如果要下班锁门,他必须确保每个角落都要去检查一遍,确保每个小朋友都离开了,才可以锁门。假设锁门是件频繁发生的事情,大爷就会非常崩溃。那大爷想了一个办法,每个小朋友进入,就把自己的名字写在本子上,小朋友离开,就把自己的名字划掉,那大爷就能方便掌握有没有小朋友在游乐场里,不必每个角落都去寻找一遍。例子中的“小本子”,就是意向锁,他记录的信息并不精细,不会记下小明是在玩木马还是在玩蹦床,他只是提醒大爷,小明在游乐场里。

InnoDB行锁模式兼容性列表:

XIXSIS
X冲突冲突冲突冲突
IX冲突兼容冲突兼容
S冲突冲突兼容兼容
IS冲突兼容兼容兼容

6. 记录锁(Record Locks)

记录锁是 封锁记录,记录锁也叫行锁,例如:

select * from test where id = 1 for update;
它会在 id=1 的记录上加上记录锁,以阻止其他事务插入,更新,删除 id=1 这一行。

记录锁、间隙锁、临键锁都是排它锁。

7. 间隙锁(Gap Locks)

当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(NEXT-KEY)锁,间隙锁只有在事务隔离级别 RR 中才会产生。

在MySQL中select称为快照读,不需要锁,而insert、update、delete、select for update则称为当前读,需要给数据加锁,幻读中的“读”即是针对当前读。

RR事务隔离级别允许存在幻读,但InnoDB RR级别却通过Gap锁避免了幻读

举个栗子,介绍间隙锁是怎么产生的:
假设有以下表t_student:(其中id为PK,name为非唯一索引)

t_student

这个时候我们发出一条这样的加锁sql语句:
select id,name from t_student where id > 0 and id < 5 for update;
这时候,我们命中的数据为以下着色部分:

t_student
细心的朋友可能就会发现,这里缺少了条id为2的记录,我们的重点就在这里。
select … for update这条语句,是会对数据记录加锁的,这里因为命中了索引,加的是行锁。从数据记录来看,这里排它锁锁住数据是id为1、3和4的这3条数据。
但是,看看前面我们的介绍——对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁。
好了,我们这里,键值在条件范围但是不存在的记录,就是id为2的记录,这里会对id为2数据加上间隙锁。假设这时候如果有id=2的记录insert进来了,是要等到这个事务结束以后才会执行的。

间隙锁的作用:
总的来说,有2个作用,防止幻读和防止数据误删/改。

  1. 防止幻读
    图1
    如果没有间隙锁,事务A在T1和T4读到的结果是不一样的,有了间隙锁,读的就是一样的了。

  2. 防止数据误删/改

    这个作用比较重要,假设以下场景:
    图2
    这种情况下,如果没有间隙锁,会出现的问题是:id为2的记录,刚加进去,就被删除了,这种情况有时候对业务,是致命性的打击。加了间隙锁之后,由于insert语句要等待事务A执行完之后释放锁,避免了这种情况。

  3. 使用间隙锁的隐患

    最大的隐患就是性能问题
    前面提到,假设这时候如果有id=2的记录insert进来了,是要等到这个事务结束以后才会执行的,假设是这种场景
    图3
    这种情况,对插入的性能就有很大影响了,必须等到事务结束才能进行插入,性能大打折扣
    更有甚者,如果间隙锁出现死锁的情况下,会更隐晦,更难定位。

总结:

  1. 对于指定查询某一条记录的加锁语句,如果该记录不存在,会产生记录锁和间隙锁,如果记录存在,则只会产生记录锁, 如:WHERE id = 5 FOR UPDATE;
  2. 对于查找某一范围内的查询语句,会产生间隙锁,如:WHERE id BETWEEN 5 AND 7 FOR UPDATE;
  3. 在普通索引列上,不管是何种查询,只要加锁,都会产生间隙锁,这跟唯一索引不一样;
  4. 在普通索引跟唯一索引中,数据间隙的分析,数据行是优先根据普通索引排序,再根据唯一索引排序。

8. 临键锁(Next-key Locks)

临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间,即会锁住一段左开右闭区间的数据。

例如查询id1-5的数据,间隙锁只会锁住2、3、4的行数据,而临建锁会锁住1、2、3、4、5这几行数据。

注:临键锁的主要目的,也是为了避免幻读(Phantom Read)。如果把事务的隔离级别降级为RC,临键锁则也会失效。

9. 自增锁

自增锁是一种比较特殊的表级锁。并且在事务向包含了AUTO_INCREMENT列的表中新增数据时就会去持有自增锁,假设事务 A 正在做这个操作,如果另一个事务 B 尝试执行INSERT语句,事务 B 会被阻塞住,直到事务 A 释放自增锁。
但是上面这种说法也不完全对,因为自增锁的实现方式有多种。

锁模式

  • 传统模式(Traditional)
  • 连续模式(Consecutive)
  • 交叉模式(Interleaved)

分别对应配置项 innodb_autoinc_lock_mode 的值0、1、2。
在这三种模式下,InnoDB 对并发的处理是不一样的,而且具体选择哪种锁模式跟你当前使用的 MySQL 版本还有关系。
在 MySQL 8.0 之前,InnoDB 锁模式默认为连续模式,值为1,而在 MySQL 8.0 之后,默认模式变成了交叉模式。

传统模式

传统模式(Traditional),说白了就是还没有锁模式这个概念时,InnoDB 的自增锁运行的模式。只是后面版本更新,InnoDB 引入了锁模式的概念,然后 InnoDB 给了这种以前默认的模式一个名字,传统模式。
当向包含了 AUTO_INCREMENT 列的表中插入数据时,都会持有这么一个特殊的表锁——自增锁(AUTO-INC),并且当语句执行完之后就会释放。这样一来可以保证单个语句内生成的自增值是连续的。这样一来,传统模式的弊端就自然暴露出来了,如果有多个事务并发的执行 INSERT 操作,AUTO-INC的存在会使得 MySQL 的性能略有下降,因为同时只能执行一条 INSERT 语句。

连续模式

连续模式(Consecutive)是 MySQL 8.0 之前默认的模式,之所以提出这种模式,是因为传统模式存在影响性能的弊端,所以才有了连续模式。
在锁模式处于连续模式下时,如果 INSERT 语句能够提前确定插入的数据量,则可以不用获取自增锁,举个例子,像 INSERT INTO 这种简单的、能提前确认数量的新增语句,就不会使用自增锁,这个很好理解,在自增值上,我可以直接把这个 INSERT 语句所需要的空间流出来,就可以继续执行下一个语句了。
但是如果 INSERT 语句不能提前确认数据量,则还是会去获取自增锁。例如像 INSERT INTO … SELECT … 这种语句,INSERT 的值来源于另一个 SELECT 语句。

交叉模式

交叉模式(Interleaved)下,所有的 INSERT 语句,包含 INSERT 和 INSERT INTO … SELECT ,都不会使用 AUTO-INC 自增锁,而是使用较为轻量的 mutex 锁。这样一来,多条 INSERT 语句可以并发的执行,这也是三种锁模式中扩展性最好的一种。
并发执行所带来的副作用就是单个 INSERT 的自增值并不连续,因为 AUTO_INCREMENT 的值分配会在多个 INSERT 语句中来回交叉的执行。

交叉模式缺点
优点很明确,缺点是在并发的情况下无法保证数据一致性。
要了解缺点具体是什么,还得先了解一下 MySQL 的 Binlog。Binlog 一般用于 MySQL 的数据复制,通俗一点就是用于主从同步。在 MySQL 中 Binlog 的格式有 3 种,分别是:

  • Statement:基于语句,只记录对数据做了修改的SQL语句,能够有效的减少binlog的数据量,提高读取、基于binlog重放的性能。

  • Row:只记录被修改的行,所以Row记录的binlog日志量一般来说会比Statement格式要多。基于Row的binlog日志非常完整、清晰,记录了所有数据的变动,但是缺点也可能会非常多,例如一条update语句,有可能是所有的数据都有修改;再例如alter table之类的,修改了某个字段,同样的每条记录都有改动。

  • Mixed:Statement和Row的结合,怎么个结合法呢。例如像alter table之类的对表结构的修改,采用Statement格式。其余的对数据的修改例如update和delete采用Row格式进行记录。

如果 MySQL 采用的格式为 Statement ,那么 MySQL 的主从同步实际上同步的就是一条一条的 SQL 语句。如果此时我们采用了交叉模式,那么并发情况下 INSERT 语句的执行顺序就无法得到保障。
INSERT 同时交叉执行,并且 AUTO_INCREMENT 交叉分配将会直接导致主从之间同行的数据主键 ID 不同。而这对主从同步来说是灾难性的。
交叉模式
由于insert语句并行执行,所以就会出现上面的情况,两个库生成的主键不一致。
换句话说,如果你的 DB 有主从同步,并且 Binlog 存储格式为 Statement,那么不要将 InnoDB 自增锁模式设置为交叉模式,会有问题。
而后来,MySQL 将日志存储格式从 Statement 变成了 Row,这样一来,主从之间同步的就是真实的行数据了,而且 主键ID 在同步到从库之前已经确定了,就对同步语句的顺序并不敏感,就规避了上面 Statement 的问题。
基于 MySQL 默认 Binlog 格式从 Statement 到 Row 的变更,InnoDB 也将其自增锁的默认实现从连续模式,更换到了效率更高的交叉模式。

鱼和熊掌不可兼得
但是如果你的 MySQL 版本仍然默认使用连续模式,但同时又想要提高性能,该怎么办呢?这个其实得做一些取舍。
如果你可以断定你的系统后续不会使用 Binlog,那么你可以选择将自增锁的锁模式从连续模式改为交叉模式,这样可以提高 MySQL 的并发。并且,没有了主从同步,INSERT 语句在从库乱序执行导致的 AUTO_INCREMENT 值不匹配的问题也就自然不会遇到了。

如何解决自增锁引起的插入性能的问题

  • 自已写一个分布式自增id的发号器,然后把主键上的 AUTO_INCREMENT 去掉;
  • 避免 insert … select … ,这样会导致Bulk inserts(插入的记录行数不能马上确定的),产生表锁;
  • 如果binlog-format是row模式,而且不关心一条bulk-insert的auto值连续(一般不用关心),那么设置innodb_autoinc_lock_mode = 2 可以提高更好的写入性能

tips:
查看引擎状态语句(包括锁、事务相关):
show engine innodb status\G
查看完整描述
set global innodb_status_output_locks=1;

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 2021-10-29

    实验二 势函数算法的迭代训练 一&#xff0e;实验目的 通过本实验的学习&#xff0c;使学生了解或掌握模式识别中利用势函数思想设计非线性判别函数的方法&#xff0c;能够实现模式的分类。学会运用已学习的先导课程如数据结构和算法设计知识&#xff0c;选用合适的数据结构完…...

    2024/5/1 1:48:01
  2. 21天养成计划(第四天)

    今天学习了让计算机执行一些数学运算。例如 #include <stdio.h> int main() { int a,b,c; scanf("%d%d%d",&a,&b,&c); int dab*c; int ea-b/c; printf("%d %d",d,e); return 0; } 学完今天的内容之后我发现&#xff0c;对于…...

    2024/5/1 0:35:36
  3. (43)Verilog HDL 二分频设计

    (43)Verilog HDL 二分频设计 1.1 目录 1)目录 2)FPGA简介 3)Verilog HDL简介 4)Verilog HDL 二分频设计 5)结语 1.2 FPGA简介 FPGA(Field Programmable Gate Array)是在PAL、GAL等可编程器件的基础上进一步发展的产物。它是作为专用集成电路(ASIC)领域中的一…...

    2024/4/30 12:38:31
  4. (44)Verilog HDL 计数器设计

    (44)Verilog HDL 计数器设计 1.1 目录 1)目录 2)FPGA简介 3)Verilog HDL简介 4)Verilog HDL 计数器设计 5)结语 1.2 FPGA简介 FPGA(Field Programmable Gate Array)是在PAL、GAL等可编程器件的基础上进一步发展的产物。它是作为专用集成电路(ASIC)领域中的一…...

    2024/4/30 23:23:26
  5. (42)Verilog HDL 打两拍设计

    (42)Verilog HDL 打两拍设计 1.1 目录 1)目录 2)FPGA简介 3)Verilog HDL简介 4)Verilog HDL 打两拍设计 5)结语 1.2 FPGA简介 FPGA(Field Programmable Gate Array)是在PAL、GAL等可编程器件的基础上进一步发展的产物。它是作为专用集成电路(ASIC)领域中的一…...

    2024/4/30 22:26:11
  6. (41)Verilog HDL D触发器设计

    (41)Verilog HDL D触发器设计 1.1 目录 1)目录 2)FPGA简介 3)Verilog HDL简介 4)Verilog HDL D触发器设计 5)结语 1.2 FPGA简介 FPGA(Field Programmable Gate Array)是在PAL、GAL等可编程器件的基础上进一步发展的产物。它是作为专用集成电路(ASIC)领域中的…...

    2024/4/30 20:33:06
  7. KW_设置root用户登录并实现远程登录05

    你也要输入普通用户的密码 注销就是退出,然后重新使用root进行登录 设置root用户登录并实现远程登录...

    2024/4/30 23:52:51
  8. 《算法0基础100讲》(第7讲)素数判定——866.回文素数

    1.素数 <1>定义&#xff1a; 一个大于1的自然数&#xff0c;除了1和它本身外&#xff0c;不能被其他自然数整除&#xff0c;换句话说就是该数除了1和它本身以外不再有其他的因数;否则称为合数。 <2>证明为素数&#xff1a; 方法1&#xff1a;如果有至少一个数用n取…...

    2024/4/30 16:18:07
  9. 组原第三张作业

    第三章一.单选题二.多选题三.填空题四.判断题第三章 一.单选题 1、挂接在总线上的多个部件&#xff08; &#xff09;。 A、只能分时向总线发送数据&#xff0c;并只能分时从总线接收数据 B、只能分时向总线发送数据&#xff0c;但可同时从总线接收数据 C、可同时向总线发送…...

    2024/4/30 16:30:30
  10. STM32学习:利用寄存器点亮LED

    /*使用普中PZ6806L开发板*/ 由对应的LED模块的电路可知&#xff0c; 要想点亮一个LED&#xff0c;就要将其对应的引脚输出低电平。 要使用寄存器&#xff0c;首先要对其进行封装&#xff0c;具体代码如下&#xff1a; #define PERIPH_BASE ((uint32_t)0x…...

    2024/4/30 0:05:24
  11. CF1400:1320A(小思维)、1312C(思维)、289B(绝对值)、1201C(模拟)

    1320A. Journey Planning&#xff08;小思维&#xff09; 题意&#xff1a; 给定一个数列ai。 从中找一个子序列&#xff0c;满足i>j, i-ja[i]-a[j]。 这样的子序列和最大为多少&#xff1f; 思路&#xff1a; 满足i-ja[i]-a[j]&#xff0c;即满足i-a[i]j-a[j]。 然后ma…...

    2024/4/24 16:02:04
  12. C语言学习(三)_21-10-28

    循环 一 while循环 #include<stdio.h>int main() {int x;int ret1;scanf("%d",&x);int tx;while(x>2){x/2;ret;}printf("log2 of %d is %d",t,ret);return 0;} #include<stdio.h>int main() {int x;int digit0;int ret0;printf(&quo…...

    2024/4/24 16:02:04
  13. 2021年12月奥鹏教育大学英语B统考题库试题(完整版)

    全国网络教育、远程教育、奥鹏教育大学英语b统考、计算机应用基础统考 2021年12月大学英语b、计算机应用基础整套原题库&#xff0c;覆盖90%以上&#xff0c;精心整理归类&#xff0c;全中文翻译&#xff0c;重点题必抽80分&#xff0c;视频教程讲解&#xff0c;复习完整套原题…...

    2024/5/1 0:24:08
  14. 输入出生年月日,分别打印

    首先出生年月日&#xff0c;年为四个数字&#xff0c;月与日都为两个数字&#xff0c;所以 然后分别打印 所以总代码为&#xff1a; #include<stdio.h> int main() { int a, b, c; scanf("%4d %2d %2d", &a, &b, &c); printf("ye…...

    2024/4/30 7:09:55
  15. Day Six -- 林深不见鹿.

    目录 计算机组成原理: 数据表示 数据库部分: leetcode每日一题: Java学习: 计算机组成原理: 数据表示 1. 基本概念 真值&#xff1a;0101&#xff0c;-0100机器数&#xff1a; [x]原0101 2. 几种机器数 原码&#xff1a;x -0101&#xff0c;[x]原 1101反码&#xff…...

    2024/4/30 22:14:29
  16. Spring - 捋明白 Spring 事务、隔离性、传播性

    事务的重要性不言而喻&#xff0c;Spring 对事务也提供了非常丰富的支持&#xff0c;各种支持的属性应有尽有。 然而很多小伙伴知道&#xff0c;这里有两个属性特别绕&#xff1a; 隔离性 传播性 1、什么是事务 数据库事务是指作为单个逻辑工作单元执行的一系列操作&#x…...

    2024/4/30 12:39:10
  17. 刷题日记(6. Z 字形变换)

    6. Z 字形变换 #define ElementType char struct MNode; typedef struct MNode* PtrToMNode; typedef PtrToMNode Vector; typedef PtrToMNode rPosition; typedef PtrToMNode bPosition;void bInsert(bPosition B); void PrintVector(Vector V); Vector CreateVector(int row)…...

    2024/4/30 19:21:08
  18. ubuntu安装,配置,制作镜像和还原

    每次换电脑或者重装都重新安装ubuntu很麻烦,不如一次配好了之后制作成镜像,一劳永逸。本文只是提纲,给自己用。1.全新安装ubuntu 官网下载ubuntu16.04 amd64镜像,用ultraISO写入U盘。在windows下用disk genius等软件划分出一块未分配空间,,如果本次安装只为了制作镜像,那…...

    2024/4/24 15:48:10
  19. Gitee协作方法(一)

    Gitee协作方法 本文主要对多人使用Gitee进行项目协作进行初步介绍 &#xff08;以在PHP storm协作为例pycharm&#xff0c;vscode等同理&#xff09; 文章目录Gitee协作方法一&#xff09;将在Gitee服务器上的项目文件拉取到本地二&#xff09;打开PHP storm三&#xff09;在本…...

    2024/4/24 15:48:09
  20. Appium有关app操作

    获取元素的属性值 方法: get_attribute(value) # value:元素的属性valuename 返回content-desc / text属性值valuetext 返回text的属性值valueclassName 返回 class属性值&#xff0c;只有 API>18 才能支持valueresourceId 返回 resource-id属性值&#xff0c;只有 API>1…...

    2024/4/30 5:44:08

最新文章

  1. Linux 虚拟主机切换php版本及参数

    我使用的Hostease的Linux虚拟主机产品,由于网站程序需要支持高版本的PHP,程序已经上传到主机&#xff0c;但是没有找到切换PHP以及查看PHP有哪些版本的位置&#xff0c;因此咨询了Hostease的技术支持&#xff0c;寻求帮助了解到可以实现在cPanel面板上找到此切换PHP版本的按钮&…...

    2024/5/1 2:27:06
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 力扣贪心算法--第一天

    前言 今天是贪心算法的第一天&#xff0c;算法之路重新开始&#xff01; 内容 之前没了解过贪心算法。 什么是贪心 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。难点就是如何通过局部最优&#xff0c;推出整体最优。 一、455.分发饼干 假设你是一…...

    2024/4/30 10:06:10
  4. mydumper和myloader对MySQL数据备份和恢复

    安装教程省略 一、mydumper数据备份 mydumper -u root -p 123456 -P 3306 -B db1 -o /data/20240329root&#xff1a;数据库用户名 123456&#xff1a;密码 3306&#xff1a;端口 db1&#xff1a;数据库库名 /data/20240329&#xff1a;导出的备份文件存放位置 导出的数据文…...

    2024/4/30 9:31:09
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/29 23:16:47
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/30 18:14:14
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/30 18:21:48
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/30 9:43:22
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57