一、修改MySQL表varchar类型 字段长度会锁表嘛?

凭借"经验"给出回答:如果字段长度超过256个字符就会锁表。
这样的回答错误 。看看MySQL 官方文档如何介绍:

Extending VARCHAR column sizeThe number of length bytes(字节) required by a VARCHAR column must remain the same. For VARCHAR columns of 0 to 255 bytes in size, one length byte is required to encode the value.For VARCHAR columns of 256 bytes in size or more, two length bytes are required. As a result, in-place ALTER TABLE only supports increasing VARCHAR column size from 0 to 255 bytes, or from 256 bytes to a greater size.  In-place ALTER TABLE does not support increasing the size of a VARCHAR column from less than 256 bytes to a size equal to or greater than 256 bytes. In this case, the number of required length bytes changes from 1 to 2, which is only supported by a table copy (ALGORITHM=COPY).

上面的意思如下:
字符串的字段是以字节为单位存储的,utf8 一个字符需要三个字节,utf8mb4 一个字符需要4个字节。对于小于等于255字节以内的长度可以使用一个byte 存储。大于255个字节的长度则需要使用2个byte存储。

online ddl in-place 模式(不锁表)只支持字段的字节长度从0到255之间 或者256到更大值之间变化。

如果修改字段的长度,导致字段的字节长度无法使用 1 byte表示,得使用2个byte才能表示,比如从 240 修改为 256 ,如果在默认字符集为utf8mb4的情况下,varchar(60) 修改为 varchar(64),则DDL需要以copy模式,也即会锁表,阻塞写操作。

另外就是不支持以 in-place 方式缩小字段长度:

Decreasing VARCHAR size using in-place ALTER TABLE is not supported. Decreasing VARCHAR size requires a table copy (ALGORITHM=COPY).

二、实践验证官方提供的说法

演示环境:演示的环境是MySQL5.7.22 二进制安装的主从复制。
下面演示的sql都是在主库上进行执行sql的。
测试表说明:
s_api_filter_abcpool_data表的字符集为utf8mb4,初始字段长度为20 ,80个字节,可以使用1byte表示。分别修改字符串长度为 60--->64--->128。当字段的字节数变动 跨越了256 则会锁表。

测试表结构如下:

root@tidb06 21:59:  [test001]> show create table s_api_filter_abcpool_data\G*************************** 1. row ***************************       Table: s_api_filter_abcpool_dataCreate Table: CREATE TABLE `s_api_filter_abcpool_data` (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键',  `bill_business_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'API主表单据ID',  `finance_core_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'Pro业务单据ID',  `bill_no` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '业务单据号',  `bill_type_code` int(10) NOT NULL DEFAULT '0' COMMENT 'Pro业务单据类型,对应api业务单据类型枚举',  `bill_type` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '单据名称',  `bill_date` varchar(128) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',  `status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '状态,0=未推送,1=已推送',  `is_red` tinyint(2) NOT NULL DEFAULT '0' COMMENT '是否红冲 0-否,1-是',  `is_wash` tinyint(2) NOT NULL DEFAULT '0' COMMENT '是否冲销 0-否,1-是',  `push_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '推送时间',  `order_no` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '订单号',  `bill_fund_type` tinyint(2) NOT NULL DEFAULT '0' COMMENT '款项类型',  `amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '金额',  `customer_id` int(11) NOT NULL DEFAULT '0' COMMENT '客户ID',  `start_date` int(20) NOT NULL DEFAULT '0' COMMENT '起始单元日',  `original_start_date` int(20) NOT NULL DEFAULT '0' COMMENT '原起始单元日',  `bill_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '账单ID',  `original_bill_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '原账单ID',  `rule_id` int(20) NOT NULL DEFAULT '0' COMMENT '对应过滤器规则ID',  `strategy_code` tinyint(2) NOT NULL DEFAULT '0' COMMENT '策略类型:1-过滤数据中的字段值,2-过滤数据中字段的计算,3-过滤数据中的字段值判断逾期天数-原财务pro过滤池策略,4-通过判断过滤子集的数据,过滤掉父集主表数据',  `rule_name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '对应过滤器名称',  `document_info` mediumtext COLLATE utf8mb4_unicode_ci COMMENT 'pro推送单据完整信息',  `completion_document_info` mediumtext COLLATE utf8mb4_unicode_ci COMMENT '补全后单据完整信息',  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',  PRIMARY KEY (`id`) USING BTREE,  KEY `idx_financeCoreId` (`finance_core_id`) USING BTREE COMMENT '核心主键索引',  KEY `idx_billBusinessId` (`bill_business_id`) USING BTREE COMMENT 'api业务表单据ID索引',  KEY `idx_billNo` (`bill_no`) USING BTREE COMMENT '单据号索引',  KEY `idx_startDate` (`start_date`) USING BTREE COMMENT '起始单元日索引',  KEY `ide_bill_type_date` (`bill_type_code`,`bill_date`) USING HASH COMMENT '单据类型+操作时间',  KEY `idx_create_time` (`create_time`) USING BTREE COMMENT '创建时间索引',  KEY `idx_customer_id` (`customer_id`) USING BTREE COMMENT '客户ID索引',  KEY `idex_billId` (`bill_id`) USING BTREE COMMENT 'billID索引') ENGINE=InnoDB AUTO_INCREMENT=1387698785715310595 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='API-过滤池存储原AB池数据表'表字符集utf8mb4 和表记录为246万行root@tidb06 22:01:  [test001]> select count(*) from s_api_filter_abcpool_data;+----------+| count(*) |+----------+|  2466560 |+----------+

开始验证测试:
ALGORITHM=INPLACE 方式 修改字段 bill_date 从 varchar(20) 到 varchar(52)

root@tidb06 22:57:  [test001]> alter table s_api_filter_abcpool_data modify bill_date varchar(52) NOT NULL DEFAULT '', ALGORITHM=INPLACE;Query OK, 0 rows affected (3 min 7.67 sec)Records: 0  Duplicates: 0  Warnings: 0

同时查看当前事务执行情况:

root@tidb06 22:59:  [(none)]> select * from information_schema.innodb_trx\G*************************** 1. row ***************************                    trx_id: 15290                 trx_state: RUNNING               trx_started: 2021-05-12 22:57:23     trx_requested_lock_id: NULL          trx_wait_started: NULL                trx_weight: 0       trx_mysql_thread_id: 1905130                 trx_query: alter table s_api_filter_abcpool_data modify bill_date varchar(52) NOT NULL DEFAULT '', ALGORITHM=INPLACE       trx_operation_state: reading clustered index         trx_tables_in_use: 1         trx_tables_locked: 0          trx_lock_structs: 0     trx_lock_memory_bytes: 1136           trx_rows_locked: 0         trx_rows_modified: 0   trx_concurrency_tickets: 0       trx_isolation_level: REPEATABLE READ         trx_unique_checks: 1    trx_foreign_key_checks: 1trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0          trx_is_read_only: 0trx_autocommit_non_locking: 01 row in set (0.00 sec)发现确实没有添加锁当前执行 SQL 的行锁数量0trx_tables_locked: 0事务保留的锁数量0trx_lock_structs: 0

ALGORITHM=INPLACE 修改字段 bill_date 从 varchar(52) 到 varchar(64):

root@tidb06 23:02:  [test001]> alter table s_api_filter_abcpool_data modify bill_date varchar(64) NOT NULL DEFAULT '', ALGORITHM=INPLACE;ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

此时只能时采用ALGORITHM=copy方式来修改:此过程非常的慢

root@tidb06 23:02:  [test001]> alter table s_api_filter_abcpool_data modify bill_date varchar(64) NOT NULL DEFAULT '', ALGORITHM=copy;
root@tidb06 23:17:  [test001]> select * from information_schema.INNODB_TRX\G*************************** 1. row ***************************                    trx_id: 15562                 trx_state: RUNNING               trx_started: 2021-05-12 23:18:59     trx_requested_lock_id: NULL          trx_wait_started: NULL                trx_weight: 6756       trx_mysql_thread_id: 1905130                 trx_query: alter table s_api_filter_abcpool_data modify bill_date varchar(64) NOT NULL DEFAULT '', ALGORITHM=copy       trx_operation_state: fetching rows         trx_tables_in_use: 2         trx_tables_locked: 3          trx_lock_structs: 284     trx_lock_memory_bytes: 24784           trx_rows_locked: 6752         trx_rows_modified: 6472   trx_concurrency_tickets: 0       trx_isolation_level: REPEATABLE READ         trx_unique_checks: 1    trx_foreign_key_checks: 1trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0          trx_is_read_only: 0trx_autocommit_non_locking: 01 row in set (0.00 sec)同时查看当前事务执行情况:当前执行 SQL 的行锁数量3 trx_tables_locked: 3 事务保留的锁数量284trx_lock_structs: 284

把字段bill_date 扩大到varchar(64)此时查看主库进程:发现在copy to tmp table

root@tidb06 23:20:  [test001]> show full processlist\G*************************** 1. row ***************************     Id: 37601   User: testrep   Host: 172.16.0.246:60158     db: NULLCommand: Binlog Dump   Time: 936618  State: Master has sent all binlog to slave; waiting for more updates   Info: NULL*************************** 2. row ***************************     Id: 1905130   User: root   Host: localhost     db: test001Command: Query   Time: 1019  State: copy to tmp table   Info: alter table s_api_filter_abcpool_data modify bill_date varchar(64) NOT NULL DEFAULT '', ALGORITHM=copy*************************** 3. row ***************************     Id: 1906899   User: root   Host: localhost     db: test001Command: Query   Time: 0  State: starting   Info: show full processlist3 rows in set (0.00 sec)
root@tidb06 23:03:  [test001]> alter table s_api_filter_abcpool_data modify bill_date varchar(64) NOT NULL DEFAULT '', ALGORITHM=copy;Query OK, 2466560 rows affected (22 min 32.83 sec)Records: 2466560  Duplicates: 0  Warnings: 0

此时查看从库会造成延迟:(延迟时间和主库的执行时间差不多)

root@tidb05 23:27:  [(none)]> show slave status\G..................................        Seconds_Behind_Master: 51Master_SSL_Verify_Server_Cert: No                Last_IO_Errno: 0                Last_IO_Error:                Last_SQL_Errno: 0               Last_SQL_Error:   Replicate_Ignore_Server_Ids:              Master_Server_Id: 172160247                  Master_UUID: da9d5c3e-a8aa-11eb-9c17-00163e0eced4             Master_Info_File: mysql.slave_master_info                    SQL_Delay: 0          SQL_Remaining_Delay: NULL      Slave_SQL_Running_State: copy to tmp table           Master_Retry_Count: 86400..................................
root@tidb05 23:30:  [(none)]> show full processlist;+---------+-------------+-----------+---------+---------+--------+----------------------------------+--------------------------------------------------------------------------------------------------------+| Id      | User        | Host      | db      | Command | Time   | State                            | Info                                                                                                   |+---------+-------------+-----------+---------+---------+--------+----------------------------------+--------------------------------------------------------------------------------------------------------+|      33 | system user |           | NULL    | Connect | 937180 | Waiting for master to send event | NULL                                                                                                   ||      34 | system user |           | test001 | Connect |   1581 | copy to tmp table                | alter table s_api_filter_abcpool_data modify bill_date varchar(64) NOT NULL DEFAULT '', ALGORITHM=copy || 1872763 | root        | localhost | NULL    | Query   |      0 | starting                         | show full processlist                                                                                  |+---------+-------------+-----------+---------+---------+--------+----------------------------------+--------------------------------------------------------------------------------------------------------+3 rows in set (0.00 sec)

nline ddl in-place 模式 字节数大于256时,也是不会锁表的
验证如下:

root@tidb06 23:32:  [test001]> alter table s_api_filter_abcpool_data modify bill_date varchar(128) NOT NULL DEFAULT '', ALGORITHM=inplace;Query OK, 0 rows affected (2 min 16.39 sec)Records: 0  Duplicates: 0  Warnings: 0root@tidb06 23:32:  [test001]> select * from information_schema.INNODB_TRX\G*************************** 1. row ***************************                    trx_id: 15684                 trx_state: RUNNING               trx_started: 2021-05-12 23:32:31     trx_requested_lock_id: NULL          trx_wait_started: NULL                trx_weight: 0       trx_mysql_thread_id: 1905130                 trx_query: alter table s_api_filter_abcpool_data modify bill_date varchar(128) NOT NULL DEFAULT '', ALGORITHM=inplace       trx_operation_state: reading clustered index         trx_tables_in_use: 1         trx_tables_locked: 0          trx_lock_structs: 0     trx_lock_memory_bytes: 1136           trx_rows_locked: 0         trx_rows_modified: 0   trx_concurrency_tickets: 0       trx_isolation_level: REPEATABLE READ         trx_unique_checks: 1    trx_foreign_key_checks: 1trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0          trx_is_read_only: 0trx_autocommit_non_locking: 01 row in set (0.00 sec)

另外就是不支持以 ALGORITHM=inplace 方式缩小字段长度。 降低varchar长度,只能采用ALGORITHM=COPY的方式

Decreasing VARCHAR size using in-place ALTER TABLE is not supported. Decreasing VARCHAR size requires a table copy (ALGORITHM=COPY).

验证如下:
order_no varchar(64) 长度从64降低到32

不支持ALGORITHM=inplace方式:

root@tidb06 22:17:  [test001]> alter table s_api_filter_abcpool_data modify  order_no varchar(32) NOT NULL DEFAULT '', ALGORITHM=inplace;ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

耗时22分钟,主库期间一直锁表:

root@tidb06 22:33:  [test001]> alter table s_api_filter_abcpool_data modify  order_no varchar(32) NOT NULL DEFAULT '', ALGORITHM=copy;Query OK, 2466560 rows affected (22 min 23.97 sec)Records: 2466560  Duplicates: 0  Warnings: 0root@tidb06 22:34:  [(none)]> select * from information_schema.INNODB_TRX\G*************************** 1. row ***************************                    trx_id: 49734                 trx_state: RUNNING               trx_started: 2021-05-16 22:34:11     trx_requested_lock_id: NULL          trx_wait_started: NULL                trx_weight: 9587       trx_mysql_thread_id: 2590351                 trx_query: alter table s_api_filter_abcpool_data modify  order_no varchar(32) NOT NULL DEFAULT '', ALGORITHM=copy       trx_operation_state: inserting         trx_tables_in_use: 2         trx_tables_locked: 3          trx_lock_structs: 1572     trx_lock_memory_bytes: 139472           trx_rows_locked: 9583         trx_rows_modified: 8015   trx_concurrency_tickets: 0       trx_isolation_level: REPEATABLE READ         trx_unique_checks: 1    trx_foreign_key_checks: 1trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0          trx_is_read_only: 0trx_autocommit_non_locking: 01 row in set (0.00 sec)

此时从库也出现了 锁表,延迟,cp临时表

      Seconds_Behind_Master: 857      Slave_SQL_Running_State: copy to tmp table trx_tables_locked: 3  trx_lock_structs: 254

参考文档连接:
https://mp.weixin.qq.com/s/R9j58nSXgKNK94PYMB-Otg

©著作权归作者所有:来自51CTO博客作者运维之美的原创作品,如需转载,请注明出处,否则将追究法律责任

如果文章对你有帮助,请赞赏

赞赏

0人进行了赞赏支持

更多相关文章

  1. PHP:MySQL常用DDL数据定义语言, DML数据库操作语言,PDO连接数据
  2. 0511 mysql基础 与 pdo作业
  3. MySQL数据库基本操作常用命令详解
  4. MSS和MTU的区别是什么?
  5. PHP面试题2021大全(二)
  6. ETL算法详解
  7. <JVM中篇:字节码与类的加载篇>04-再谈类的加载器
  8. <JVM中篇:字节码与类的加载篇>03-类的加载过程(类的生命周期)详解
  9. <JVM中篇:字节码与类的加载篇>01-Class字节码文件结构

随机推荐

  1. Android 自定义渐变背景
  2. 关于新版SDK报错You need to use a Theme
  3. android小配置junit测试环境
  4. android Intent API8
  5. 10个android开发必备的开源项目
  6. 代码调用Android应用程序卸载
  7. 这些年正Android - 大纲
  8. 协程中的取消和异常 | 核心概念介绍
  9. 月薪8k到年入60w!Android毕业生开发三年做
  10. Binder框架的一些简单总结(关于自定义服务