先说总结:
- 以业务优先,如果必须要数据库保证数据的唯一性,那么必须使用唯一索引。
- 不需要通过数据库来保证唯一性的情况下,建议使用普通索引,理由是普通索引可以使用
change buffer
机制,直接将对读到内存的数据页的数据进行更改,之后再写盘。而唯一索引不支持change buffer
.
区别
1、查询过程
例子:select id from T where k=5
,其中k是带有索引的键。该语句在索引树上查找的过程,先从B+树的树根开始,按层搜索叶子结点,可以认为数据叶内部通过二分法来定位数据。
- k为普通索引:找到满足条件的第一个
k=5
的记录后,需要找下一个记录,知道碰到不符合该条件的记录。 - k为唯一索引:索引具有唯一性,找到来第一个满足记录的记录,就停止搜索。
然而,这里带来的性能差距可以用四个字来描述:微乎其微!
不过,InnoDB的数据是按照数据页为单位来读写的,从磁盘中读入数据页到内存中。这对于普通索引来说,如果找到第一个记录需要再读入下一个数据页继续搜索直到找到不符合k=5
的数据,这种情况会复杂一些。但是一个数据页可以存放key的数量一般较多,这种情况的概率很低,可以忽略不计。
2.更新过程
更新过程必须要谈到change buffer
。
change buffer
是用来在内存中缓存更新操作的,当需要更新一个数据页时,如果数据在其中就将其更新缓存在其中,直接更新内存,不再需要立刻从磁盘中读入这个数据页了。PS:change buffer
中的数据也是可以持久化到磁盘的数据;change buffer
其大小可以通过参数 innodb_change_buffer_max_size 来动态设置。
将change buffer
中的操作应用到原数据页得到最新结果的过程,称为merge
。触发merge的行为包括访问最新数据页、系统后台定期merge,数据库正常关闭。
使用change buffer
的好处就是:可以减少数据读盘,提高访问性能;避免读盘数据,占用内存(buffer pool
),可以提高内存的利用率。
然而,唯一索引在数据页不在内存中时,他必须读入数据页,以判断是否存在唯一性约束(插入操作),所以他没法使用buffer pool
,对于普通索引而言,只要更新内存就行了。将数据从磁盘读入内存涉及到随机IO的访问,是数据库成本最高的操作之一。
但是,并不是所有情况下,普通索引使用change buffer
都可以起到加速作用。例如,如果一个业务的更新模式,是写入之后马上会做查询,会立即merge操作,这样随机访问IO的次数并没有减少,相反增加了change buffer
的维护代价。