普通索引和唯一索引,应该怎么选择?

676 阅读5分钟

如果市民系统需要按照身份证号查姓名,那么我们会在id——card添加索引,那我们就需要去考虑到底是用普通索引还是唯一索引呢?

为什么不把身份证号当主键呢?

因为每个索引都会携带主键,身份证所占据的资源比较大,所以我们不会将身份证设置为主键.

用唯一索引和普通索引查这个语句,性能有什么差异?

select id from T where k=100

对于普通索引来说,查找到满足条件的第一个记录 (100,200) 后,需要查找下一个记录,直到碰到第一个不满足 k=100 条件的记录。

对于唯一索引来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。

但是这个造成的性能的差异是很小的,因为mysql每一次从磁盘上加载一个页的数据大小是16kb,在内存中查询的数据是很快的,所有不会产生很大的数据的差异。

change buffer的作用?

当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了。

在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。需要说明的是,虽然名字叫作 change buffer,实际上它是可以持久化的数据。也就是说,change buffer 在内存中有拷贝,也会被写入到磁盘上。

将 change buffer 中的操作应用到原数据页,得到最新结果的过程称为 merge。除了访问这个数据页会触发 merge 外,系统有后台线程会定期 merge。在数据库正常关闭(shutdown)的过程中,也会执行 merge 操作。

为什么唯一索引不使用change buffer? 对于唯一索引来说,所有的更新操作都要先判断这个操作是否违反唯一性约束。比如,要插入 (4,40) 这个记录,就要先判断现在表中是否已经存在 k=4 的记录,而这必须要将数据页读入内存才能判断。

如果都已经读入到内存了,那直接更新内存会更快,就没必要使用 change buffer 了。因此,唯一索引的更新就不能使用 change buffer,实际上也只有普通索引可以使用。

使用唯一索引以及普通索引执行更新语句的性能分析?

第一种情况是,这个记录要更新的目标页在内存中。

这时,InnoDB 的处理流程如下:对于唯一索引来说,找到 3 和 5 之间的位置,判断到没有冲突,插入这个值,语句执行结束;对于普通索引来说,找到 3 和 5 之间的位置,插入这个值,语句执行结束。这样看来,普通索引和唯一索引对更新语句性能影响的差别,只是一个判断,只会耗费微小的 CPU 时间。

第二种情况是,这个记录要更新的目标页不在内存中。

对于唯一索引来说,需要将数据页读入内存,判断到没有冲突,插入这个值,语句执行结束;对于普通索引来说,则是将更新记录在 change buffer,语句执行就结束了。

什么时候适合用change buffer?什么时候不适合?

对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时 change buffer 的使用效果最好。这种业务模型常见的就是账单类、日志类的系统。

反过来,假设一个业务的更新模式是写入之后马上会做查询,那么即使满足了条件,将更新先记录在 change buffer,但之后由于马上要访问这个数据页,会立即触发 merge 过程。这样随机访问 IO 的次数不会减少,反而增加了 change buffer 的维护代价。所以,对于这种业务模式来说,change buffer 反而起到了副作用。

redo log 和 change buffer的差异?

redo log 与 change buffer(含磁盘持久化) 这2个机制,不同之处在于——优化了整个变更流程的不同阶段。 先不考虑redo log、change buffer机制,简化抽象一个变更(insert、update、delete)流程: 1、从磁盘读取待变更的行所在的数据页,读取至内存页中。 2、对内存页中的行,执行变更操作 3、将变更后的数据页,写入至磁盘中。 步骤1,涉及 随机 读磁盘IO; 步骤3,涉及 随机 写磁盘IO; Change buffer机制,优化了步骤1——避免了随机读磁盘IO Redo log机制, 优化了步骤3——避免了随机写磁盘IO,将随机写磁盘,优化为了顺序写磁盘(写redo log,确保crash-safe) -------------------------------- 在我们mysql innodb中, change buffer机制不是一直会被应用到,仅当待操作的数据页当前不在内存中,需要先读磁盘加载数据页时,change buffer才有用武之地。 redo log机制,为了保证crash-safe,一直都会用到。 ------------------------------- 有无用到change buffer机制,对于redo log这步的区别在于—— 用到了change buffer机制时,在redo log中记录的本次变更,是记录new change buffer item相关的信息,而不是直接的记录物理页的变更。