现象:在线上环境,一条慢查询没有用到索引,表大小适中,加索引实际在3-5S内,决定在线添加。
mysql版本:5.1.56-community-log ,plugin innodb版本:1.0.15。
在添加索引的过程中,有原来的慢查询对此表进行访问,程序端返回错误:
"1412: Table definition has changed, please retry transaction (172.16.0.100)".
检查错误日志,里面也记录了相应的错误信息:
130324 3:55:55 [ERROR] Got error 159 when reading table './DB1/TB1' 130324 3:55:55 [ERROR] Got error 159 when reading table './DB1/TB1' 130324 3:55:55 [ERROR] Got error 159 when reading table './DB1/TB1'
分析159,1412错误,错误信息显示说表定义已经改变了,要重做事务。
[root@devdb7 ~]# perror 159 MySQL error code 159: The table changed in storage engine [root@devdb7 ~]# perror 1412 MySQL error code 1412 (ER_TABLE_DEF_CHANGED): Table definition has changed, please retry transaction
分析:
Alter table tbname add index idx_X(column_name);是一个标准的Alter table 流程,引擎内部操作流程是:
1 If a transaction is open on this thread, commit it. 2 Acquire a read lock for the table. 3 Make a temporary table with new structure 4 Copy the old table to the temporary table row by row changing the structure of the rows on the fly. 5 Rename the original table out of the way 6 Rename the temporary table to the original table name. 7 Drop the original table. 8 Release the read lock.
在1-4步的过程中,别的session可以正常访问这个表,到5的时候,会阻塞别的访问,状态提示是:“Waiting for tables”,然后等待。
前面1412的错误并不是这个。考虑到innodb 不是built in,而是plugin innodb,它实现了Fast Index Creation,是不是这个新特性造成的?
从mysql官方文档可以看到
Prior to InnoDB storage engine 1.0.4, unexpected results could occur if a query attempts to use an index created after the start of the transaction containing the query. If an old transaction attempts to access a “too new” index,
InnoDB storage engine 1.0.4 and later reports an error: ERROR HY000: Table definition has changed, please retry transaction As the error message suggests, committing (or rolling back) the transaction, and restarting it, cures the problem.
在1.0.4或之后的innodb plugin里面,事务访问新索引会提示1412信息,然后事务中断。此错误并没造成多大的影响,相对1.0.4之前的返回异常结果,已经做了优化了。
对于这样的错误信息的处理方法是:As the error message suggests, committing (or rolling back) the transaction, and restarting it, cures the problem.