唯一索引和普通索引都是我们常见的索引,在MYSQL中,也是我们经常使用到的索引。那么我们应该在适当的时候使用两个索引。可能一般我们都能脱口而出:当值是唯一的时候就使用唯一索引,其他的时候为了增加查询速度可以使用普通索引。
查询速度
先说结论:实际上我们的唯一索引和普通索引的查询速度是差不多的。
两种索引是如何工作的?假设我们有条语句:select id from T where k=5
普通索引:在索引k上查找到第一个满足条件的记录:k=5,继续向下遍历如果碰到第一个k!=5 停止并返回数据
唯一索引:在索引上找到第一个满足条件的记录:k=5 返回数据
区别:其实看似我们的普通索引在找到对应的值后还要继续遍历数据但是其实这个操作
第一:是在内存中操作的。第二:遍历只向后,数据量很少,如果程序可以控制,那么这个步骤时间可以忽略不记。
查询过程
我们知道innodb是按照页来进行读写内容的,也就是要读一条记录,本身并不是直接读该条记录。而是直接将数据所在的页返回给内存,再在内存中进行查找对应的条数据。如下图
![](https://img.haomeiwen.com/i17592436/8c0dc1132fdd7e12.png)
对于普通索引,在内存中只是多了一次指针向下的操作,并不会影响速度,所以查询效率来说唯一索引和普通索引其实一样的。
但是也有问题哈,在几千分之一的情况下,刚好查询的id=5的记录在数据页最下方,向下指针操作还需要读一个页面,innodb的单页面是16kb,一个页面能存储整形字段大概能存上千,概率还是很小的。
更新过程&&change buffer
聊完查询过程,我们聊以下更新过程吧。
什么是change buffer,这里就可以从字面上理解了,就是数据改变之前的缓冲。我们知道磁盘操作时数据库性能消耗的瓶颈,也就是我们常常说的随机IO访问。有了change buffer 有什么好处呢,这里就要从更新数据说起。我们更新数据,如果数据在内存页中就直接更新内存,如果内存中没有数据,就将要更新的数据放到了changebuffer中,当用户查询的这个数据的时候,就会查询磁盘的最新页,然后将change buffer数据 merge到最新页面中。所有操作是在内存中完成的。
值得说明的是,其实change buffer 也是存在磁盘中的,所以就不用担心数据丢失。merge有几个条件可以触发,后台是有独立线程定时更新的,访问该条数据也可以触发数据库merge,数据库正常关闭也会发生merge。
change buffer 和索引
所有的索引都会使用到change buffer 吗? 不是的,我们想以下唯一索引和普通索引的更新数据
唯一索引:先将磁盘数据页读取到内存,判断要插入数据是否存在
普通索引:直接将数据写入change buffer
对于唯一索引来说,必须判断数据是否存在,所以将数据页读入内存是必不可少的操作,所以会直接更新内存,而不用change buffer, 对于普通索引则不需要在内存判断,减少了读磁盘的次数,所以cpu消耗会比较小,也减少了内存的占用。
所以大部分条件下我推荐的是用程序来确定数据唯一,减少使用唯一索引的使用。
change buffer 是万能药吗
前面我们说了我们要减少唯一索引的使用,多使用普通索引。那么changebuffer是万能药吗,任何东西都是两面的,change buffer 也是一样。
我们说过change buffer 是在用户查询的时候就会merge,也就是这个特性,如果我们有个订单记录,插入了过后,就要看订单详情,那么这个changebuffer 就会带来负面影响,这个时候我们就可将changebuffer关闭掉。如果是日志型应用,存入的时候并不需要立刻查看,那么changebuffer 就可以产生最优的应用场景。
其实这里我也提出了一些问题,希望大家留言探讨,merge是在内存中操作的还是最加写入到磁盘呢,在内存中更新的输入如何保存到磁盘的?我本人其实对这两点是比较疑惑的,欢迎探讨
原创文章,转发请标明出处
网友评论