字符串的字段是以字节为单位存储的,utf8字符集的表 一个字符需要三个字节,utf8mb4字符集的表 一个字符需要4个字节。对于小于等于255字节以内的长度可以使用一个byte 存储。大于255个字节的长度则需要使用2个byte存储。如果表字段varchar长度从1到85之间变化的话,改字段的存储字节最大也就是255,一个byte足够存储。此时varchar在1到85长度之间变化,是不会锁表的。但是varchar的长度从小于等于85直接修改到大于85的话,此时他的字节数以及大于255了,存储到磁盘需要至少2个byte.此时DDL需要以copy模式,即会锁表,阻塞写操作。
演示如下:
表记录数
root@node04 20:04: [db_bill]> select count(*) from t_order_bill_detail_change_log
-> ;
+----------+
| count(*) |
+----------+
| 1792992 |
+----------+
1 row in set (2.26 sec)
原始字段varchar长度:
`main_order_id` varchar(20) NOT NULL COMMENT ‘主订单号‘,
字段varchar长度从20到85 不存在锁表:
ALTER TABLE t_order_bill_detail_change_log MODIFY COLUMN `main_order_id` varchar(85) NOT NULL COMMENT ‘主订单号‘;
root@node04 20:18: [db_bill]> ALTER TABLE t_order_bill_detail_change_log MODIFY COLUMN `main_order_id` varchar(85) NOT NULL COMMENT ‘主订单号‘;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
字段长度:
`main_order_id` varchar(85) NOT NULL COMMENT ‘主订单号‘,
字段varchar 长度从85到86发生锁表:
发生锁表,耗时64秒:
root@node04 20:26: [db_bill]> ALTER TABLE t_order_bill_detail_change_log MODIFY COLUMN `main_order_id` varchar(86) NOT NULL COMMENT ‘主订单号‘;
Query OK, 1792992 rows affected (1 min 4.07 sec)
Records: 1792992 Duplicates: 0 Warnings: 0
发生了锁表:
root@node04 20:28: [information_schema]> select * from information_schema.INNODB_TRX\G
*************************** 1. row ***************************
trx_id: 2395935
trx_state: RUNNING
trx_started: 2021-07-26 20:28:18
trx_requested_lock_id: NULL
trx_wait_started: NULL
trx_weight: 9961
trx_mysql_thread_id: 4
trx_query: ALTER TABLE t_order_bill_detail_change_log MODIFY COLUMN `main_order_id` varchar(86) NOT NULL COMMENT ‘主订单号‘
trx_operation_state: fetching rows
trx_tables_in_use: 2
trx_tables_locked: 3
trx_lock_structs: 154
trx_lock_memory_bytes: 24784
trx_rows_locked: 9957
trx_rows_modified: 9807
trx_concurrency_tickets: 0
trx_isolation_level: REPEATABLE READ
trx_unique_checks: 1
trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_adaptive_hash_latched: 0
trx_adaptive_hash_timeout: 0
trx_is_read_only: 0
trx_autocommit_non_locking: 0
1 row in set (0.00 sec)
字段长度大于86:
main_order_id
varchar(86) NOT NULL COMMENT ‘主订单号‘,
修改 字段varchar 长度 从86到比86大的数值 也不会发生锁表的问题:
ALTER TABLE t_order_bill_detail_change_log MODIFY COLUMN `main_order_id` varchar(172) NOT NULL COMMENT ‘主订单号‘;
root@node04 21:00: [db_bill]> ALTER TABLE t_order_bill_detail_change_log MODIFY COLUMN `main_order_id` varchar(172) NOT NULL COMMENT ‘主订单号‘;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
字符集为utf8mb4 也是一样的。此处不再介绍了,感兴趣的话,可以测试下。