MySQL索引(10)- 普通索引和唯一索引

最后更新:2018-04-10

对于select * from t where k=5,这个查询预警在B+树按层级搜索(定位数据页),然后在+ 数据页内部通过二分法来定位记录

  • 如果k是唯一索引,由于索引定义了唯一性,查找到第一个满足条件的记录后就会停止继续减少,只需要一次搜索树操作
  • 如果k是普通索引,查找到第一个满足条件的记录后,还需要查找下一个记录,直到碰到第一个不满足k=5的记录(读取下一个索引值,并比较),但不需要重新执行搜索树操作

局部性原理:当需要读取一条数据的时候,innodb会将整个页读取到内存。

普通索引查找下一个记录,直到碰到第一个不满足k=5的记录的操作只需要一次指针寻找和一次计算。如果k=5这个记录刚好是这个数据页的最后一个记录,要取下一页还需要读取下一个数据页(一页可以存储大量数据,这个事件发生的改了很低)

所以, 普通索引和唯一索引的查询性能基本一直。但是如果业务能保证数据唯一性,我们应该尽量选择普通索引,这是为什么呢?

因为无论是inset还是update操作,如果数据页不在内存页中,innodb都需要从磁盘读取数据到内存,会触发一次随机读IO的操作。为了提升写操作的性能更,innodb引入了change buffer。如果数据页不在缓冲池,并不会立即将数据页加载到缓冲池,而是先将修改记录保存到 Change Buffer。等到未来Change Buffer数据对应的数据页被读取到缓冲区时合并到真正的数据页中。(如果数据页已经在缓冲池中了,直接修改缓冲页中的数据)

Change Buffer

唯一索引在进行插入或修改操作时,InnoDB必须进行唯一性检查。如果不读取索引页到缓冲池中,无法校验索引是否唯一(如果将写操作记录在change buffer当中,则无法检测到多次插入操作之间是否有冲突)

  • 如果目标页在缓冲池中,只需要找到对应的位置,判断没有冲突,插入新值
  • 如果目标页不在缓冲池中,需要将数据页读取到缓冲中,判断没有冲突,插入新值

因为将数据从磁盘读取到缓冲中涉及随机IO的访问,是数据库里面成本最高的操作之一。change buffer因为减少了随机IO,对更新性能会有显著提示。所以对于写多读少的情况,建议尽量选择普通索引。

Edgar

Edgar
一个略懂Java的小菜比