MySQL加索引导致的问题

增加主键索引会锁表

  1. 在navicat中开一个窗口,执行以下语句:
BEGIN;
select * from ur_user where id = '0000000053843f8901538447f27c0002';
-- COMMIT;
  1. 再开另外一个窗口,执行以下语句:
ALTER TABLE `ur_user` ADD PRIMARY KEY ( `id` ) 
  1. 再开第三个窗口,执行以下语句:
SHOW PROCESSLIST;

第三个窗口发现如下内容,说明即使增加主键索引,会锁表。这点毫无疑问,因为我们查询是用的该主键。
在这里插入图片描述
如果我们提交第一步中的COMMIT,则会释放表锁,第2步中的增加索引会执行。
在这里插入图片描述

猜想应该增加非主键索引应该不会锁表。看下以下示例。

增加二级索引也会锁表

  1. 在navicat中开一个窗口,执行以下语句:
BEGIN;
select * from ur_user where id = '0000000053843f8901538447f27c0002';
-- COMMIT;
  1. 再开另外一个窗口,执行以下语句:
ALTER TABLE `ur_user` ADD  KEY `idx_mobile_tel` (`mobile_tel`)
  1. 再开第三个窗口,执行以下语句:
SHOW PROCESSLIST;

第三个窗口发现如下内容,说明即使增加非主键索引,也同样会锁表。
在这里插入图片描述
执行第一个窗口中的COMMIT语句,发现锁表解除。
在这里插入图片描述

为啥增加二级索引也会锁表?

先从我们的metadata lock说起,为了在并发环境下维护表元数据的数据一致性,在表上有活动事务(显式或隐式)的时候,不可以对元数据进行写入操作。因此从MySQL5.5版本开始引入了MDL锁(metadata lock),来保护表的元数据信息,用于解决或者保证DDL操作与DML操作之间的一致性。
对于引入MDL,其主要解决了2个问题,一个是事务隔离问题,比如在可重复隔离级别下,会话A在2次查询期间,会话B对表结构做了修改,两次查询结果就会不一致,无法满足可重复读的要求;另外一个是数据复制的问题,比如会话A执行了多条更新语句期间,另外一个会话B做了表结构变更并且先提交,就会导致slave在重做时,先重做alter,再重做update时就会出现复制错误的现象。所以在对表进行上述操作时,如果表上有活动事务(未提交或回滚),请求写入的会话会等待在Metadata lock wait 。
支持事务的InnoDB引擎表和不支持事务的MyISAM引擎表,都会出现Metadata Lock Wait等待现象。一旦出现Metadata Lock Wait等待现象,后续所有对该表的访问都会阻塞在该等待上,导致连接堆积,业务受影响。

所以为了解决这些问题,所以就会在创建索引时会出现锁表的情况。

常见的MDL锁场景

  1. 当前有执行DML操作时执行DDL操作,尤其是长事务运行时,阻塞DDL,从而阻塞同表的后续操作,将导致灾难性的后果。
  2. 当前有对表的长时间查询或使用mysqldump/mysqlpump时,使用alter会堵住
  3. 显式或者隐式开启事务后未提交或回滚,比如查询完成后未提交或回滚,将导致DDL会被堵住。

常见处理方式

以上测试是通过结束掉该事务。但是生成很多时候是没办法控制应用的事务提交的。我们通常采用以下方式解决。

  1. kill 40968; – 通过kill掉DDL所在的session.
  2. 如果show processlist看不到刚才未提交的事务,可以通过 select * from information_schema.innodb_trx\G, 找到未提交事物的sid, 然后 kill 掉,让其回滚。
  3. 通过show processlist看不到TableA上有任何操作,在information_schema.innodb_trx中也没有任何进行中的事务。这很可能是因为在一个显式的事务中,对TableA进行了一个失败的操作(比如查询了一个不存在的字段),这时事务没有开始,但是失败语句获取到的锁依然有效,没有释放。从performance_schema.events_statements_current表中可以查到失败的语句。

总之,alter table的语句是很危险的(其实他的危险其实是未提交事物或者长事务导致的),在操作之前最好确认对要操作的表没有任何进行中的操作、没有未提交事务、也没有显式事务中的报错语句。如果有alter table的维护任务,在无人监管的时候运行,最好通过lock_wait_timeout设置好超时时间,避免长时间的metedata锁等待。

参考:https://dev.mysql.com/doc/refman/5.7/en/where-optimization.html

猜你喜欢

转载自blog.csdn.net/gonghaiyu/article/details/108349486