本文從5.1.48下的一個bug說起。前提是新特性fast index creation.
1、現象
5.1.48 (innodb plugin 1.0.9)
session1
session2
create table tb(a int)engine=innodb;
insert into tb values(1),(2),(3),(4),(5);
begin;
select * from tb where a=3;
a
3
alter table tb add index a(a);
error 2013 (hy000): lost connection to mysql server during query
說明:session1提示lost connection,實際上mysql已經dump了。
2、分析
這個結果還是比較好了解的。有fast index creation,預設不需要重作表,是以沒有表鎖。
session1開始于加索引之前,第一個select語句使用的是全表掃描,第二個select語句執行時,索引已經建好,是以查詢時候使用索引a。這在實作上就可能觸發諸多雷區(實際上概念上都已經錯誤,下文描述)。
在這個版本的實作中,由于建立索引導緻第二次select時候使用了prebuilt-> search_tuple. 這個結構在事務開始前沒有初始化,是以在嘗試使用時類型判斷錯誤直接abort。(row0sel.c)
3、最新版本的實作
由于5.1.48在我們線上用的比較普遍,是以特别查了這個版本的實作和原因。在5.1最新版本中已經避免了這個問題;5.5最新版本也避免了,但有趣的是,兩個版本的實作機制完全不同。
我們先列出兩個版本的效果再讨論。
5.1.61的效果
5.1.61 (innodb plugin 1.0.17)
error 1412 (hy000): table definition has changed, please retry transaction
5.5.19的效果
5.5.19
lock here
可以看到,兩個版本的實作方法不同。5.1裡面通過判斷索引生成時間與事務開始時間的差别,提示使用者需要重新開機事務。
5.5則是作了個鎖更新,鎖住加索引操作。并且這個操作不影響session1的一緻性讀。(當然很容易想到在session1執行一個更新操作是什麼效果)。
政策上5.5的實作更符合repeatable-read的概念。
4、其他
說明下,5.1的其他版本未試驗。