憑藉"經驗"給出回答:若是字段長度超過256個字符就會鎖表。
這樣的回答錯誤 。看看MySQL 官方文檔如何介紹:mysql
Extending VARCHAR column size The 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存儲。sql
online ddl in-place 模式(不鎖表)只支持字段的字節長度從0到255之間 或者256到更大值之間變化。api
若是修改字段的長度,致使字段的字節長度沒法使用 1 byte表示,得使用2個byte才能表示,好比從 240 修改成 256 ,若是在默認字符集爲utf8mb4的狀況下,varchar(60) 修改成 varchar(64),則DDL須要以copy模式,也即會鎖表,阻塞寫操做。less
另外就是不支持以 in-place 方式縮小字段長度:ide
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 則會鎖表。測試
測試表結構以下:fetch
root@tidb06 21:59: [test001]> show create table s_api_filter_abcpool_data\G *************************** 1. row *************************** Table: s_api_filter_abcpool_data Create 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)ui
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
同時查看當前事務執行狀況:this
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: 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) 發現確實沒有添加鎖 當前執行 SQL 的行鎖數量0 trx_tables_locked: 0 事務保留的鎖數量0 trx_lock_structs: 0
ALGORITHM=INPLACE 修改字段 bill_date 從 varchar(52) 到 varchar(64):code
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: 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) 同時查看當前事務執行狀況: 當前執行 SQL 的行鎖數量3 trx_tables_locked: 3 事務保留的鎖數量284 trx_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: NULL Command: 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: test001 Command: 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: test001 Command: Query Time: 0 State: starting Info: show full processlist 3 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: 51 Master_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: 0 root@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: 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)
另外就是不支持以 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: 0 root@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: 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)
此時從庫也出現了 鎖表,延遲,cp臨時表
Seconds_Behind_Master: 857 Slave_SQL_Running_State: copy to tmp table trx_tables_locked: 3 trx_lock_structs: 254