各位好久不见了。。换了个新排版。鲁迅说过,脱更只有0次和Integer.MAX_VALUE次,这两天忙着找房子,租的房子马上过期了,找个合适太费事了,要么贵要么远要么不干净。不过鲁迅还说过没有什么事是一顿火锅解决不了的。

创建MySQL表的时候创建唯一索引并命名 mysql如何创建唯一索引_mysql 创建唯一索引

辗转多地实地考察终于找到合适的房子了,所以下周可能还得鸽,得搬家嘛。。。房子是腿哥先找到的(腿哥房子也快到期了),但是被我用一顿火锅挖墙脚了。顺便过一过1024嘛~

创建MySQL表的时候创建唯一索引并命名 mysql如何创建唯一索引_mysql 创建唯一索引_02

如何选择唯一索引还是普通索引

创建MySQL表的时候创建唯一索引并命名 mysql如何创建唯一索引_mysql 联合唯一索引_03

先简单提一下普通索引与唯一索引的区别。

  • 普通索引(key或index)的唯一任务就是加快对数据的访问速度,所以经常加在查询条件或者排序条件列中,
  • 唯一索引(unique)如果能确定某个数据列将只包含彼此各不相同的值,就应该用关键字UNIQUE定义一个唯一索引。MySQL会在有数据插入的时候,检查新记录的这个字段的值是否已经存在,如果存在则插入失败,也就是说,唯一索引可以保证数据记录的唯一性。

查询性能差异


按照之前的B+树索引结构,对于普通索引来说,查到满足条件的第一个记录后还需要继续查找下一个记录,直到碰到第一个不满足条件的记录而唯一索引由于定义了唯一性在找到第一个满足条件的记录后就停止检索了。

这个不同带来的性能差距微乎其微。具体为啥呢,因为大家都这么说。。。

创建MySQL表的时候创建唯一索引并命名 mysql如何创建唯一索引_mysql创建唯一索引_04

InnoDB的数据是按数据页为单位来读写的。也就是说,当需要读一条记录的时候,并不是将这个记录本身从磁盘读出来,而是以页为单位,将其整体读入内存。只要不是下一条记录正好在下一页(不会发生磁盘io)性能差距就不会很大

更新性能差异


changebuffer

当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InooDB会将这些更新操作缓存在change buffer中。

等未来数据被读取时,将磁盘中的数据页读入内存,然后执行change buffer中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。

将change buffer中的操作应用到原数据页,得到最新结果的过程称为merge,避免大量磁盘随机io。除了访问这个数据页会触发merge外,系统有后台线程会定期merge。将数据从磁盘读入内存涉及随机IO的访问,是数据库里面成本最高的操作之一,显然只要减少了磁盘访问语句的执行速度就会提升很多。

什么条件下可以使用changebuffer
如果索引设置了唯一属性,在进行修改操作时,InnoDB必须进行唯一性检查。也就是说,索引页即使不在缓冲池,也会读取磁盘上的数据页用来检测是否符合唯一,失去了意义。

这两类索引主要考虑的是对更新性能的影响。所以,在没有唯一性约束的情况下尽量选择普通索引。如果所有的更新后面,都马上伴随着对这个记录的查询,那么你应该关闭change buffer。因为查询频次越低changebuffer的收益越高。而在其他情况下,change buffer都能提升更新性能。

changebuffer与redos
大家读过之前那片鲁迅喝酒赊账写粉板的那篇mysql文章可能会有点迷瞪,放个连接>鲁迅喝酒  因为我一开始看这个就很迷糊。。。这跟那个鲁迅的粉板(redolog)似乎一个意思。

是这样。WAL一旦由需要写入的内容时,先写在黑板上,当黑板上写不下的时候或者有空闲的时候,再将黑板上的内容都拷贝到账本中。黑板,在Mysql中对应日志(redo log); 账本,对应Mysql中的磁盘。而两阶段提交是为了保证数据库的目前状态和它通过日志恢复出来的库的状态一致。

假设有个表k,有两个字段field1,field2,执行以下sql。

insert into t(id,k) values(id1,k1),(id2,k2);

然后假如k1 所在的插入位置的数据页page1在内存 中, k2位置 所在的数据页不在内存中。那么捋一下执行逻辑。

创建MySQL表的时候创建唯一索引并命名 mysql如何创建唯一索引_mysql创建唯一索引_05

1、 Page 1 在内存中(buffer pool中),直接更新内存,直接把数据插入到表t中的位置

2、Page 2 没有在内存中,就在内存的 change buffer 区域,记录下 “ 我要往 Page 2 插入一行 ” 这个信息

3、将上述两个动作记入 redo log 中(图中 3 和 4 )(包含了数据的变更和 change buffer 的变更)

select * from t where k in (k1, k2)

然后执行一下查询请求,k1在page1中,page1在内存中直接返回,而page2需要把 Page 2 从磁盘读入内存中,然后应用 change buffer 里面的操作日志(add 某个数据 to page2).最后生成正确的版本并返回结果。

总结一下就是redo log 主要节省的是随机写磁盘的IO消耗(转成顺序写),而change buffer主要节省的则是随机读磁盘的IO消耗。