MySQL:为什么要优先使用普通索引而尽量避免使用唯一索引不同类型的索引。今天我们就来说说普通索引和唯一索引的使用场景,以及为什么建议大家优先使用普通索引,尽量避免使用唯一索引。对于普通的二级索引,其目的是为了加快查询速度,所以我们可能会针对表中的某个字段或部分字段创建普通的二级索引。至于唯一索引,由于其唯一键约束的特点,有时我们会赋予它更多的业务意义。比如有一张表,里面存放的是身份证号。为了保证身份证号的唯一性,我们会在身份证号字段上创建唯一索引。那么为什么不建议大家使用唯一索引呢?下面我们从查询和更新两个方面来分析唯一索引和普通索引的性能差距。查询性能我们知道每个索引其实就是一棵二叉树,所以我简单画了一张索引图,不太好看,还请多多包涵。让我向您解释一下这张照片。不同的颜色代表不同的数据页。这里假设在一个数据页中存储了两个数据。我们知道MySQL磁盘和内存是通过一个叫做数据页的单元进行交互的,每个数据页的默认大小是16K。在一棵树中,只有叶子节点才能真正存储数据,非叶子节点存储的是每个下级数据页中的最小索引字段和指向下级数据页的指针。对于主键索引,叶子节点存储一行真实数据,而对于二级索引,叶子节点存储索引字段和对应的主键id。好了,我们来分析下普通的二级索引和唯一索引是如何查找数据的?以一个简单的查询sql为例:selectidfromtwherem=103;1,MySQL从根节点开始,通过二分法判断m=103大于100小于104,所以会找到数据页100对应根节点-102中的100;2、在100-102的数据页上,由于103大于102,所以会找到102对应的102-103的数据页;3、在这个数据页上,找到m=103的记录,获取到要查询的id字段。对于普通的二级索引,找到第一条m=103的记录后,会继续向后查找,判断104-105数据页中是否有满足m=103条件的记录,没有则结束查询.对于唯一索引,由于其唯一性约束,找到第一条记录后搜索结束。可见两者的区别在于是否继续寻找下一项。两者的性能差距有多大?答案几乎没有。我们知道MySQL数据是以页为单位存储的。以一个int类型的二级索引为例,一个int占4个字节,加上6个字节的MySQL头信息,相当于10个字节。那么一个16k的页面可以存储多少条记录呢?16*1024/10=1638,也就是说一个数据页上可能有1600多条记录。那么当我们查询数据的时候,整个数据页就会被加载到内存中。这个时候普通二级索引的确定下一条记录操作需要的消耗是非常非常小的。可以说,从查询的角度来看,普通二级索引和唯一索引的性能基本相当。更新性能唯一索引与普通二级索引的性能差距主要体现在更新操作上。对于MySQL,更新语句的逻辑是先读取要更新的记录,如果记录不在内存中,则先加载到内存中。然后执行updated语句,然后将变化的数据刷新到磁盘。但是对于MySQL来说,从磁盘读取数据到内存会涉及到随机IO,这是一个非常昂贵的操作。如果每次更新数据都必须这样做,可能很难保证高性能。因此,设计MySQL的大师们引入了一个叫做changebuffer的东西。变化缓冲区是一种可以持久化的缓存数据。当我们要更新数据时,如果要更新的数据在内存中不存在,此时我们不需要将数据从磁盘加载到内存中,而是将更新操作记录在changebuffer中,更新操作完成。下次要读取数据时,将读取到的数据合并到changebuffer中,即merge。通过changebuffer,update操作不需要读磁盘,整个过程就是一次内存操作,性能自然可以大大提升。但!但是问题又来了!changebuffer只对普通二级索引有效,对唯一索引无效。为什么?因为在更新记录时,我们需要检查索引的唯一性约束。如何检查?自然要先将数据从磁盘加载到内存中才能做出判断。但是如果数据已经加载到内存中,那么使用更改缓冲区就多余了。因此,唯一索引不能,也没有必要使用更改缓冲区来提高性能。由于唯一索引的更新涉及到读取磁盘的随机IO操作,性能自然不如普通二级索引。这也是为什么建议大家优先使用普通二级索引的原因。通过对比也可以看出,这两个索引的查询性能基本一致,性能差距主要体现在更新操作上。其实即使你有一些特殊的业务需求,比如存储唯一的身份证号,也建议你通过业务层来限制。一般来说,普通二级索引比唯一索引能带来更大的收益。
