若是业务能保证惟一性的状况下,仍是选择普通索引性能更好mysql
select id from T where k=5sql
首先,咱们看下数据库
对于普通索引来讲,查询到知足条件的第一个记录后,须要查找下一个记录,直到碰到第一个不知足k=5条件的记录性能
对于惟一索引来讲,因为索引上有惟一性,查询到第一个知足条件的记录后就中止检索了线程
因此在这里的区别就是普通索引会多查那么一下,那么这两种的性能差异有多大呢?指针
答案是微乎其微,为甚呢?日志
由于mysql在读数据的时候,好比说上面那条语句,若是没有在内存中,会去磁盘中把k=5这条数据所在的整个数据页都读入内存中,在innodb中,每一个数据页的大小默认是16KB,由于引擎是按页读写的,因此说,当找到k=5的记录的时候,它所在的数据页都在内存里了,那么对于普通索引来讲,要多作的那一次查询的操做,就只须要一次指针寻找和一次计算,固然,若是K=5这个记录恰好是这个数据页的最后一个记录,那么要取下一个记录,必须读取下一个数据页,这个操做会稍微复杂一些,可是对于整形字段,一个数据页能够放近千个key,所以出现这种状况的几率会很低,因此,咱们计算平均性能差别时,扔能够认为这个操做成本对于如今的cpu来讲能够忽略不计。索引
首先咱们说下change_buffer的概念,若是要更新的数据在内存中,那么就直接更新内存,若是要更新的数据没有在内存中,那么就会把更新记录存在change_buffer中,等到有查询来读取数据页的时候,就会执行change_buffe中有关这个数据页的操做。经过这种方式就能保证这个数据逻辑的正确性。内存
change_buffer也会持久化到磁盘,将change_buffer中的操做应用到原数据页,获得最新结果的过程称为merge,除了访问这个数据页会触发merge外,系统有后台线程会按期merge,在数据库正常关闭的过程当中,也会执行mergeio
显然若是可以将更新操做记录在change_buffer,减小读磁盘,语句的执行速度会获得明显的提高。并且,数据读入内存是须要占用buffer pool的,因此这种方式还可以避免占用内存,提升内存利用率
那么什么条件下可使用changebuffer呢?
对于惟一索引来讲,每次更新都必须先判断这个操做是否违反惟一性约束,好比,要插入(4,400)这个记录,就要先判断如今表中是否存在这个记录,而这必需要将数据页读入内存才能判断,既然都读入内存了,那么直接更新内存会更快,就不必使用change buffer了。
所以,惟一索引的更新就不能使用change buffer
change buffer用的是buffer pool里的内存,由于不能无限增大,change buffer的大小,能够经过参数innodb_change_buffer_max_size来动态设置,这个参数设置为50的时候,表示change buffer的大小最多只能占用buffer pool的50%
如今咱们看下若是要在这张表中插入一个新记录(4,400)的话,innodb的处理流程是什么样的
第一种状况是,这个记录要更新的目标页在内存中,这时,innodb的处理流程以下:
这样看来,普通索引和惟一索引对更新语句性能影响的差异,只是一个判断,只会耗费微小的CPU时间。
但,这不是咱们关注的重点
第二中状况是,这个记录要更新的目标页不在内存中,这时,流程以下:
将数据从磁盘读入内存涉及随机io的访问,是数据库里面成本最高的操做之一。changebuffer由于减小了随机磁盘访问,因此对更新性能的提高是会很明显的
可是change buffer的应用场景只是对于写多读少的的业务,页面在写完之后立刻被访问的几率比较小,此时changebuffer的使用效果最好,这种业务模型常见的就是帐单类,日志类的系统。
反过来,若是一个业务的更新模式是写完以后立刻会作查询,那么即便知足了条件,将更新记录在change buffer,但以后因为立刻要访问这个数据页,会当即触发Merge过程,这样随机访问io的次数不会减小,反而增长了change buffer的维护代价。因此,对于这种业务模式来讲,change buffer反而起到了副作用。
因此,若是全部的更新后面,都立刻伴随着对这个记录的查询,那么你应该关闭change buffer,而在其余状况下,change buffer都能提高更新性能。
小结
若是业务能保证一个字段的惟一性而且针对的是写多多少的业务模式,那么仍是选择普通索引的好。