MySQL 的 MRR 到底是什么?( 二 )


当一个数据被用到时,其附近的数据也通常会马上被使用 。
3、在一次查询中,每一页的数据只会从磁盘读取一次MySQL 从磁盘读取页的数据后,会把数据放到数据缓冲池,下次如果还用到这个页,就不需要去磁盘读取,直接从内存读 。
但是如果不排序,可能你在读取了第 1 页的数据后,会去读取第2、3、4页数据,接着你又要去读取第 1 页的数据,这时你发现第 1 页的数据,已经从缓存中被剔除了,于是又得再去磁盘读取第 1 页的数据 。
而转化为顺序读后,你会连续的使用第 1 页的数据,这时候按照 MySQL 的缓存剔除机制,这一页的缓存是不会失效的,直到你利用完这一页的数据,由于是顺序读,在这次查询的余下过程中,你确信不会再用到这一页的数据,可以和这一页数据说告辞了 。
顺序读就是通过这三个方面,最大的优化了索引的读取 。别忘了,索引本身就是为了减少磁盘 IO,加快查询,而 MRR,则是把索引减少磁盘 IO 的作用,进一步放大 。尾声和 MRR 相关的配置 有两个:

  • mrr: onoff
  • mrr_cost_based: onoff
第一个就是上面演示时用到的,用来打开 MRR 的开关:
mysql > set optimizer_switch='mrr=on';如果你不打开,是一定不会用到 MRR 的 。
另一个,则是用来告诉优化器,要不要基于使用 MRR 的成本,考虑使用 MRR 是否值得(cost-based choice),来决定具体的 sql 语句里要不要使用 MRR 。
很明显,对于只返回一行数据的查询,是没有必要 MRR 的,而如果你把 mrr_cost_based 设为 off,那优化器就会通通使用 MRR,这在有些情况下是很 stupid 的,所以建议这个配置还是设为 on,毕竟优化器在绝大多数情况下都是正确的 。
另外还有一个配置 read_rnd_buffer_size ,是用来设置用于给 rowid 排序的内存的大小,显然, MRR 在本质上是一种用空间换时间的算法 ,MySQL 不可能给你无限的内存来进行排序,如果 read_rnd_buffer 满了,就会先把满了的 rowid 排好序去磁盘读取,接着清空,然后再往里面继续放 rowid,直到 read_rnd_buffer 又达到 read_rnd_buffe 配置的上限,如此循环 。




推荐阅读