索引使用时遇到的问题(顺丰)--InnoDB引擎不使用自增主键导致性能问题,也可答最左前缀

InnoDB自增主键

InnoDB主索引(同时也是数据文件)的示意图:

上文讨论过InnoDB的索引实现,InnoDB使用聚集索引,数据记录本身被存于主索引(一颗B+Tree)的叶子节点上。这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(InnoDB默认为15/16),则开辟一个新的页(节点)。(一个页(节点)不止一条记录)

如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置(自增主键,新纪录id一定比老的大,而前面说过同一个叶子节点内的各条数据记录按主键顺序存放),当一页写满,就会自动开辟一个新的页。如下图所示:

这样就会形成一个紧凑的索引结构,近似顺序填满。由于每次插入时也不需要移动已有数据,因此效率很高,也不会增加很多开销在维护索引上。

如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置:

此时MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增加了很多开销,同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。

基于聚簇索引的表在插入新行,或者主键被更新导致需要移动行的时候,可能面临“页分裂”的问题。当行的主键值要求必须将这一行插入到某个已满的页中时,存储引擎会将该页分裂成两个页面来容纳该行,这就是一次分裂操作。页分裂会导致表占用更多的磁盘空间。

因此,只要可以,请尽量在InnoDB上采用自增字段做主键。

顺序主键什么时候回造成更会坏的结果?

对于高并发工作负载,在InnoDB中按主键顺序插入可能会造成明显的争用。主键上界会成为”热点”,因为所有的插入都发生在这里,所以并发插入可能导致间隙锁竞争。另一个热点可能是AUTO_INCREMENT锁机制:如果遇到这个问题,则可能需要考虑重新设计表或者应用,或者更改innodb_autoinc_lock_mode配置。

自增长在数据库中是非常常见的一种属性,也是很多DBA或开发人员首选的主键方式。在InnoDB存储引擎的内存结构中,对每个含有自增长值的表都有一个自增长计数器。当对含有自增长的计数器的表进行插入操作时,这个计数器会被初始化,执行如下的语句来得到计数器的值:

 
1
select max(auto_inc_col) from t for update;

插入操作会依据这个自增长的计数器值加1赋予自增长列。这个实现方式称为AUTO-INC Locking。这种锁其实是采用一种特殊的表锁机制,为了提高插入的性能,锁不是在一个事务完成后才释放,而是在完成对自增长值插入的SQL语句后立即释放。

虽然AUTO-INC Locking从一定程度上提高了并发插入的效率,但还是存在一些性能上的问题。首先,对于有自增长值的列的并发插入性能较差,事务必须等待前一个插入的完成,虽然不用等待事务的完成。其次,对于INSERT….SELECT的大数据的插入会影响插入的性能,因为另一个事务中的插入会被阻塞。

从MySQL 5.1.22版本开始,InnoDB存储引擎中提供了一种轻量级互斥量的自增长实现机制,这种机制大大提高了自增长值插入的性能。并且从该版本开始,InnoDB存储引擎提供了一个参数innodb_autoinc_lock_mode来控制自增长的模式,该参数的默认值为1。在继续讨论新的自增长实现方式之前,需要对自增长的插入进行分类。如下说明:

  • insert-like:指所有的插入语句,如INSERT、REPLACE、INSERT…SELECT,REPLACE…SELECT、LOAD DATA等。
  • simple inserts:指能在插入前就确定插入行数的语句,这些语句包括INSERT、REPLACE等。需要注意的是:simple inserts不包含INSERT…ON DUPLICATE KEY UPDATE这类SQL语句。
  • bulk inserts:指在插入前不能确定得到插入行数的语句,如INSERT…SELECT,REPLACE…SELECT,LOAD DATA。
  • mixed-mode inserts:指插入中有一部分的值是自增长的,有一部分是确定的。入INSERT INTO t1(c1,c2) VALUES(1,’a’),(2,’a’),(3,’a’);也可以是指INSERT…ON DUPLICATE KEY UPDATE这类SQL语句。

接下来分析参数innodb_autoinc_lock_mode以及各个设置下对自增长的影响,其总共有三个有效值可供设定,即0、1、2,具体说明如下:

  • 0:这是MySQL 5.1.22版本之前自增长的实现方式,即通过表锁的AUTO-INC Locking方式,因为有了新的自增长实现方式,0这个选项不应该是新版用户的首选了。
  • 1:这是该参数的默认值,对于”simple inserts”,该值会用互斥量(mutex)去对内存中的计数器进行累加的操作。对于”bulk inserts”,还是使用传统表锁的AUTO-INC Locking方式。在这种配置下,如果不考虑回滚操作,对于自增值列的增长还是连续的。并且在这种方式下,statement-based方式的replication还是能很好地工作。需要注意的是,如果已经使用AUTO-INC Locing方式去产生自增长的值,而这时需要再进行”simple inserts”的操作时,还是需要等待AUTO-INC Locking的释放。
  • 2:在这个模式下,对于所有”INSERT-LIKE”自增长值的产生都是通过互斥量,而不是AUTO-INC Locking的方式。显然,这是性能最高的方式。然而,这会带来一定的问题,因为并发插入的存在,在每次插入时,自增长的值可能不是连续的。此外,最重要的是,基于Statement-Base Replication会出现问题。因此,使用这个模式,任何时候都应该使用row-base replication。这样才能保证最大的并发性能及replication主从数据的一致。

这里需要特别注意,InnoDB跟MyISAM不同,MyISAM存储引擎是表锁设计,自增长不用考虑并发插入的问题。因此在master上用InnoDB存储引擎,在slave上用MyISAM存储引擎的replication架构下,用户可以考虑这种情况。

另外,InnoDB存储引擎,自增持列必须是索引,同时必须是索引的第一个列,如果不是第一个列,会抛出异常,而MyiSAM不会有这个问题。

 
1
2
mysql>createtabletest(idintprimarykeynotnull,countintauto_incrementnotnull);
ERROR1075(42000):Incorrecttabledefinition;therecanbeonlyoneautocolumnanditmustbedefinedasakey

--------------------- 本文来自 onyas 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/zheng0518/article/details/76302167?utm_source=copy

https://blog.csdn.net/zheng0518/article/details/76302167?utm_source=copy

为什么推荐InnoDB引擎使用自增主键?的更多相关文章

  1. INNODB自增主键的一些问题

    背景: 自增长是一个很常见的数据属性,在MySQL中大家都很愿意让自增长属性的字段当一个主键.特别是InnoDB,因为InnoDB的聚集索引的特性,使用自增长属性的字段当主键性能更好,这里要说明下自增 ...

  2. INNODB自增主键的一些问题 vs mysql获得自增字段下一个值

    今天发现 批量插入下,自增主键不连续了....... InnoDB AUTO_INCREMENT Lock Modes This section describes the behavior of A ...

  3. mysql的innodb自增主键为什么不是连续的

    图1 图1中是表t原有的数据,这个时候我们执行show create table t会看到如下输出,如图二所示现在的自增值是2,也就是下一个不指定主键值的插入的数据的主键就是2 图2 Innodb引擎 ...

  4. Innodb自增主键与sql_mode

    1.自增主键 1.设置自增主键 建表设置自增主键,设置自增主键需要唯一约束,否则会报错.(即指定列数据唯一) mysql> create table test_zz(id int auto_in ...

  5. 《Mysql - 自增主键为何不是连续的?》

    一:自增主键是连续的么? - 自增主键不能保证连续递增. 二:自增值保存在哪里? - 当使用 show create table `table_name`:时,会看到 自增值,也就是 AUTO_INC ...

  6. MySQL 中的自增主键

    MySQL 的主键可以是自增的,那么如果在断电重启后新增的值还会延续断电前的自增值吗?自增值默认为1,那么可不可以改变呢?下面就说一下 MySQL 的自增值. 特点 保存策略 1.如果存储引擎是 My ...

  7. java面试一日一题:mysql中的自增主键

    问题:请讲下mysql中的自增主键 分析:该问题主要考察对mysql中自增主键的掌握,使用场景及如何设置 回答要点: 主要从以下几点去考虑 1.什么自增主键 2.使用场景是什么: 3.innodb_a ...

  8. MySQL8自增主键变化

    MySQL8自增主键变化 醉后不知天在水,满船清梦压星河. 一.简述 MySQL版本从5直接大跃进到8,相信MySQL8一定会有很多令人意想不到的改进,如果不想只会CRUD可以看看. 比如系统表引擎的 ...

  9. MySQL主从复制数据不一致问题【自增主键】

    前言: 今天遇到主从表不一致的情况,很奇怪为什么会出现不一致的情况,因为复制状态一直都是正常的.最后检查出现不一致的数据都是主键,原来是当时初始化数据的时候导致的.现在分析记录下这个问题,避免以后再遇 ...

随机推荐

  1. Notepad++和Sublime单词首字符大小写转化问题

  2. Eclipse的Jar包解压出System.js里String与Boolean定义分号可有可无吗?

    Eclipse的Jar包解压出System.js里String与Boolean定义分号可有可无吗? org.eclipse.wst.jsdt.core_1.3.300.v201410221502\li ...

  3. Wordpress 更新时 不输入ftp相关信息的方法

    From 百度知道 我自己机器上面的处理过程为: cd /usr/share/nginx/html vim wp-config.php 在配置文件里面插入这三行 define("FS_MET ...

  4. 基于C#.NET的高端智能化网络爬虫(二)(攻破携程网)

    本篇故事的起因是携程旅游网的一位技术经理,豪言壮举的扬言要通过他的超高智商,完美碾压爬虫开发人员,作为一个业余的爬虫开发爱好者,这样的言论我当然不能置之不理.因此就诞生了以及这一篇高级爬虫的开发教程. ...

  5. 软件工程_6th weeks

    一.上次博客时说的UI,拖拉到现在才展示,完成了“登录,普通匹配,做题界面,做题结果”四项 功能: 二.单元测试工具 1.python单元测试工具   最近因为论文原因一直在用Python,Pytho ...

  6. 美国运营商推送假5G图标:用户当场蒙圈了

    面对5G大潮,大家都想“争当第一”.美国运营商AT&T想出奇招,打算玩一把“障眼法”. 据外媒报道,AT&T的用户从明年开始会在手机右上角看到“5G E”的图标.当然,这并不是他们的手 ...

  7. ELK--filebeat nginx模块

    Nginx模块 该nginx模块解析由Nginx HTTP服务器创建的访问和错误日​​志 . 当你运行这个模块的时候,它会执行一些任务: 设置日志文件的默认路径(但不用担心,可以覆盖默认值) 确保每个 ...

  8. 最小费用最大流spfa

    #include <iostream> #include <cstring> #include <cstdio> #include <queue> #d ...

  9. 说 AppbarLayout,如何理解可折叠 Toolbar 的定制

    Material Design 是个好东西,它的出现使得 Android 也能定制高颜值的界面,并且指导了如果实现复杂炫丽的交互效果,而 android Surpport Desgin 这个支持包就是 ...

  10. BZOJ 1778: [Usaco2010 Hol]Dotp 驱逐猪猡

    1778: [Usaco2010 Hol]Dotp 驱逐猪猡 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 563  Solved: 216[Submi ...