1.性能对比
(1)查询过程
假设执行查询的语句是:select * from T where k=5,首先在B+树上搜索到在哪个页,然后在页内部通过二分法进行查找;
普通索引:查找到第一个k=5的记录之后,会继续往下查找,直到找到一个不满足k=5的记录就停止;
唯一索引:索引定义了唯一性,所以找到第一个记录之后就不会往下查找了。
那这个不同对性能影响大吗?
众所周知,InnoDB的数据是按照数据页为单位进行读写的,在查询一条记录的时候,是把整个页加载到内存里面的,一页的大小是16KB,如果k=5的记录都在同一页上面,那性能差距微乎其微,如果k=5的记录是跨页的,性能差距会相对大一些,取决于跨了多少页,考虑到1页的大小是16kb,那如果存储8个字节的整型数据的话可以存储2000个左右,我们正常查询数据也不会查询这么多,所以跨页的情况总体来说也不多。
总结:通过以上分析,普通索引和唯一索引在查找性能上相差不大,唯一索引会稍微好一些。
(2)更新过程
首先需要理解什么是change buffer?
更新数据时如果数据页就在内存中则可以直接更新,如果不在内存中,正常流程则需要把数据页先读取到内存中,然后再进行更新,这里的读取会涉及磁盘的随机io,比较消耗性能,所以就引入了change buffer在内存中先把更新操作保存起来,而不进行读取操作,写入数据时减少了随机io,提升了写入性能。
那change buffer什么时候执行呢?
第一种情况就是系统定期执行,第二种情况就是如果这个时候有查询操作过来了,那必须得读取数据然后进行更新了。
所以如果对于刚刚更新就需要读取的情况,chang buffer会影响查询速度。
对于唯一索引,由于需要判断插入的数据是否在数据库中是否已经有了,那每次插入都必须先读取页数据到内存中,然后进行判断,然后在内存中做变更,所以唯一索引不能使用change buffer。
总结:插入性能唯一索引比普通索引要差一些。
2.如何选择
(1)从查询性能角度考虑,唯一索引的查询性能略胜普通索引,但是插入性能唯一索引比普通索引差得较多,所以如果是读多写少的场景唯一索引略胜一筹,如果是读少写多的场景普通索引略胜一筹;
(2)从业务角度考虑,如果某个字段需要保证唯一性,那最好还是使用唯一索引来保证,防止产生脏数据对业务功能造成影响,当然mysql的唯一索引只是保证唯一性的一种方式,也可以使用其它的方式保证数据唯一性。
3.其它思考
(1)之前在线上碰到过:前一天把普通索引改成了唯一索引,第二天发现这张表的性能急剧下降,后面分析应该就是唯一索引插入的性能比普通索引性能差一些,所以导致的这个问题;
(2)对于一些“归档库”其实是可以把普通索引改成唯一索引的,因为主库已经保证了唯一性了,唯一索引改成普通索引,可以让归档速度更快。