MySQL5.5加主键锁读问题—续

205 阅读2分钟
原文链接: click.aliyun.com
背景

        上一篇说到MySQL 5.5加主键导致阻塞源表的读的问题。

有同学提到从调用函数看,在默认的old_alter_table=off的情况下,加主键过程没有看到copy to tmp table。

         这里我们再细说一下。

 

说说fast index creation

         在MySQL 5.1以后InnoDB引入了fast index creation。在有这个feature之前,MySQL认为所有的加减索引操作都必须创建临时表、拷贝数据、删除源表。

         有了这个神奇的功能之后,InnoDB跟MySQL说,稍等,要是加索引,不要你拷贝数据了,“放着我来”。怎么作的呢?

1)       扫描源表,将每行中用于索引的字段取出来

2)       排序构造新索引

3)       插入源表中

这个就是我们说的inplace-DDL了,大家看到,没有拷贝新表的操作。性能因此也提高了。这个过程叫做row_merge_build_indexes。

 

再说说加主键

         对于InnoDB来说,数据也是以索引组织的,因此加主键,在概念上说,也是加索引。于是在old_alter_table=off的情况下,MySQL照着上面的约定,调用row_merge_build_indexes。

         由于在5.5,MySQL认为InnoDB还是inplace操作,因此锁策略就如同上一篇处理。

 

         那么InnoDB是不是在源表加主键呢?

         这显然不可能。

         Fast-index-creation的精髓是只需要读主键数据,生成新索引插入到源表中。若加的是主键,说明原来没有定义主键(多么正确的废话),这时候InnoDB是使用系统分配的row_id作为主键。当我们增加主键以后,不可能“构造主键,插入源表”----那样就俩主键了。。。

 

源码实现

         实际上row_merge_build_indexes有两个参数(old_table, new_table)。 若新增的索引中不包含主键,则new_table == old_tablie,否则不等。

         对于不等的情况,这个过程就变成

1)       扫描old_table主键上的数据

2)       按照新增的索引插入到new_table中

3)       而由于“主键”索引的叶子节点,实际上是包含所有数据,所以这个过程,其实就是copy table。

 

对于new_table!=old_table的情况,在拷贝数据期间只需要加共享锁即可,只是5.5下没有意识到这个问题而已。