MYSQL 生产环境字段更改的failed的问题如何解决
这篇文章主要介绍"MYSQL 生产环境字段更改的failed的问题如何解决",在日常操作中,相信很多人在MYSQL 生产环境字段更改的failed的问题如何解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"MYSQL 生产环境字段更改的failed的问题如何解决"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
早上看到微信一个银行的同学问了小问题,希望他不要背锅,具体问题是MYSQL 一个50G的表要更改字段,将一个字段从varchar(3) 改成varchar(6). MYSQL 5.7 官版。因为根据官方和在测试系统测试的结果来看,不应该是缓慢的,应该是很快完成的。
VARCHAR列所需的长度字节数必须保持相同。对于大小为0到255个字节的VARCHAR列,需要一个长度的字节来编码该值。对于大小为256字节或更大的VARCHAR列,需要两个长度的字节。结果,就地ALTER TABLE仅支持将VARCHAR列大小从0增大到255字节,或从256字节增大到更大的大小。就地ALTER TABLE不支持将VARCHAR列的大小从少于256个字节增加到等于或大于256个字节的大小。在这种情况下,所需的长度字节数从1更改为2,这仅由表副本支持(ALGORITHM = COPY)。
所以我们要理解一个事情首先要站在一个起跑线上,上面的东西都是官方文档,并且在测试环境上测试基本上没有太大问题。
可能原因如下
1 DDL ONLINE 不阻塞 DML 但并没有说,不会不阻塞 DDL 的操作
2 测试环境比较单纯,可能测试的时候,对表并没有其他的复杂的操作
所以还是那句话,数据库的问题,一定要想的复杂点,理论上很多事情说的很明白,解析的很明白,但到了实际当中,可能就会不一样了。
我也做了一个测试
1 我弄了一个存储过程,并且不断往一个表里面插入数据
2 我将这表里面的某个字段从200 变化到 201
3 我的语句严格按照官方的语句去撰写,不给不严谨的操作留下半点口实
存储过程就不展示了,主要是太简单了,表就是下面的表,content字段是varchar(200) -> varchar(201)
alter table test1 modify column content varchar(201), algorithm=inplace,lock=none;
但实际上,这条语句一直在等待的状态,根据官方文档,如果他在执行的时候,应该是不会对DML 操作有影响。但如果他根本就在等待 metadata lock呢。所以修改字段的任务依然是失败的。
到底是为什么,官方在文档中明确了
为了确保事务的可串行性,服务器必须不允许一个会话对另一个会话中未完成的显式或隐式启动的事务中使用的表执行数据定义语言(DDL)语句。服务器通过获取事务中使用的表的元数据锁,并将这些锁的释放推迟到事务结束时,来实现这一点。表上的元数据锁可以防止对表结构的更改。这种锁定方法意味着一个会话内的事务正在使用的表,不能在DDL状态下使用。
但让我感到奇怪的事情是,当我停止了存储过程不断 对这个表进行操作,DDL的语句也未在执行,并且就卡在哪里。
而在kill 掉所有的有关线程后,再次做这个实验,惊奇的是不在有MDL LOCK 来阻碍 alter 的操作,基本上都是瞬间在0.几秒的时间就完成了。
总结一下
DB的工作本身是一件复杂的工作,他并没有你在理解原理后,就一定会按照你认为的那样,去工作,因为理论和实际遇到的情况不同,实际的情况太多种多样。
有些公司操作ALTER 语句的并不是人工,而是通过购买(或开源)的一个所谓的 "自动化"工具来的,谁也不知道在故障发生的一刻,做了什么,同时不能复制的,就是当时的生产环境到底有没有大事务,并且就对那张表进行了什么操作,那个表有几个索引,这个字段有没有索引,等等。
也注定 DB的工作,是一件需要小心小心小心的工作,因为生产环境一定有你不清楚的环境,而这些可能不清楚的环境,就会让某次"信心满满"的Action Failed.
注:到目前为止MYSQL 在修改字段方面,对比其他数据库还是要注意的地方多多,当然MYSQL 8 已经添加了 instant 让修改字段变得更让人放心。
但目前MYSQL5.X PT-OSC GH-OST等等的工具还是用起来,终归是不希望出现意外的情况。
下面有一个查看metadatalock的存储过程,(有点乱,可以拷贝出来,自己整理一下)
CREATE PROCEDURE procShowMetadataLockSummary()
BEGIN
DECLARE table_schema VARCHAR(64);
DECLARE table_name VARCHAR(64);
DECLARE id bigint;
DECLARE time bigint;
DECLARE info longtext;
DECLARE curMdlCount INT DEFAULT 0;
DECLARE curMdlCtr INT DEFAULT 0;
DECLARE curMdl CURSOR FOR SELECT * FROM tmp_blocked_metadata;
DROP TEMPORARY TABLE IF EXISTS tmp_blocked_metadata;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_blocked_metadata (
table_schema varchar(64),
table_name varchar(64),
id bigint,
time bigint,
info longtext,
PRIMARY KEY(table_schema, table_name)
);
REPLACE tmp_blocked_metadata(table_schema,table_name,id,time,info) SELECT mdl.OBJECT_SCHEMA, mdl.OBJECT_NAME, t.PROCESSLIST_ID, t.PROCESSLIST_TIME, t.PROCESSLIST_INFO FROM performance_schema.metadata_locks mdl JOIN performance_schema.threads t ON mdl.OWNER_THREAD_ID = t.THREAD_ID WHERE mdl.LOCK_STATUS='PENDING' and mdl.LOCK_TYPE='EXCLUSIVE' ORDER BY mdl.OBJECT_SCHEMA,mdl.OBJECT_NAME,t.PROCESSLIST_TIME ASC;
OPEN curMdl;
SET curMdlCount = (SELECT FOUND_ROWS());
WHILE (curMdlCtr < curMdlCount)
DO
FETCH curMdl INTO table_schema, table_name, id, time, info;
SELECT CONCAT_WS(' ','PID',t.PROCESSLIST_ID,'has metadata lock on', CONCAT(mdl.OBJECT_SCHEMA,'.',mdl.OBJECT_NAME), 'with current state', CONCAT_WS('','[',t.PROCESSLIST_STATE,']'), 'for', t.PROCESSLIST_TIME, 'seconds and is currently running', CONCAT_WS('',"[",t.PROCESSLIST_INFO,"]")) AS 'Process(es) that have the metadata lock' FROM performance_schema.metadata_locks mdl JOIN performance_schema.threads t ON t.THREAD_ID = mdl.OWNER_THREAD_ID WHERE mdl.LOCK_STATUS='GRANTED' AND mdl.OBJECT_SCHEMA = table_schema and mdl.OBJECT_NAME = table_name AND mdl.OWNER_THREAD_ID NOT IN(SELECT mdl2.OWNER_THREAD_ID FROM performance_schema.metadata_locks mdl2 WHERE mdl2.LOCK_STATUS='PENDING' AND mdl.OBJECT_SCHEMA = mdl2.OBJECT_SCHEMA and mdl.OBJECT_NAME = mdl2.OBJECT_NAME);
SELECT CONCAT_WS(' ','PID', id, 'has been waiting for metadata lock on',CONCAT(table_schema,'.', table_name),'for', time, 'seconds to execute', CONCAT_WS('','[',info,']')) AS 'Oldest process waiting for metadata lock';
SET curMdlCtr = curMdlCtr + 1;
SELECT CONCAT_WS(' ','PID', t.PROCESSLIST_ID, 'has been waiting for metadata lock on',CONCAT(table_schema,'.', table_name),'for', t.PROCESSLIST_TIME, 'seconds to execute', CONCAT_WS('','[',t.PROCESSLIST_INFO,']')) AS 'Other queries waiting for metadata lock' FROM performance_schema.metadata_locks mdl JOIN performance_schema.threads t ON t.THREAD_ID = mdl.OWNER_THREAD_ID WHERE mdl.LOCK_STATUS='PENDING' AND mdl.OBJECT_SCHEMA = table_schema and mdl.OBJECT_NAME = table_name AND mdl.OWNER_THREAD_ID AND t.PROCESSLIST_ID <> id ;
END WHILE;
CLOSE curMdl;
END//
delimiter ;
到此,关于"MYSQL 生产环境字段更改的failed的问题如何解决"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!