精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

MySQL 擴(kuò)展字段長度報錯 Specified key was too long

數(shù)據(jù)庫 MySQL
MySQL 5.5 中引入 innodb_large_prefix 參數(shù),5.5 與 5.6 中該參數(shù)默認(rèn)關(guān)閉,5.7 中默認(rèn)開啟。innodb_large_prefix 參數(shù)用于控制行格式 ?DYNAMIC or COMPRESSED 中的索引最大長度。

引言

本文主要分析一套 MySQL 分庫分表擴(kuò)展字段長度時其中一個實(shí)例報錯索引超長的案例,其中失敗實(shí)例的版本是 5.7.21,而成功實(shí)例的版本都是 5.7.24。因此懷疑與版本有關(guān),最終通過測試與分析判斷是一個 bug,官方文檔顯示在 5.7.23 中修復(fù)。

現(xiàn)象

首先介紹三個案例,都是字段長度擴(kuò)展時報錯索引超長。

案例 1

時間:2023-09-08 21:31:02

數(shù)據(jù)庫版本:5.6.39

SQL

ALTER TABLE sign_bill_return_image_audit_result 
MODIFY COLUMN image_name VARCHAR(250) COMMENT '圖片名稱';

日志顯示 pt-osc 執(zhí)行期間報錯索引長度超過 767。

EXECUTE START AT 2023-09-08 21:31:02
Error altering new table `station_manager`.`_sign_bill_return_image_audit_result_new`: DBD::mysql::db do failed: Specified key was too long; max key length is 767 bytes [for Statement "ALTER TABLE `station_manager`.`_sign_bill_return_image_audit_result_new` MODIFY COLUMN image_name VARCHAR(250) COMMENT '圖片名稱';"] at /usr/bin/pt-online-schema-change line 9194.

EXECUTE FAIL AT 2023-09-08 21:31:03

查看表結(jié)構(gòu),顯示字符集為 utf8mb4,索引類型為單列唯一索引,image_name 字段長度從 50 擴(kuò)展到 250。

mysql> show create table station_manager.sign_bill_return_image_audit_result \G
*************************** 1. row ***************************
       Table: sign_bill_return_image_audit_result
Create Table: CREATE TABLE `sign_bill_return_image_audit_result` (
  `image_name` varchar(50) NOT NULL DEFAULT '' COMMENT '圖片名稱',
  UNIQUE KEY `idx_img_name` (`image_name`) USING BTREE,
) ENGINE=InnoDB AUTO_INCREMENT=27756774 DEFAULT CHARSET=utf8mb4 COMMENT='簽單返還圖片審核結(jié)果表'
1 row in set (0.00 sec)

查看參數(shù),顯示未開啟 innodb_large_prefix。

mysql> show variables like 'innodb_large_prefix';
+---------------------+-------+
| Variable_name       | Value |
+---------------------+-------+
| innodb_large_prefix | OFF   |
+---------------------+-------+
1 row in set (0.00 sec)

案例 2

時間:2024-08-19 14:18:31

現(xiàn)象:上游字段擴(kuò)展,因此下游修改,但是執(zhí)行報錯聯(lián)合索引超長

數(shù)據(jù)庫版本:5.7.33

SQL

alter table worker_board_quota_counting 
modify column  `business_id` varchar(1456) NOT NULL COMMENT '業(yè)務(wù)id';

日志顯示 pt-osc 執(zhí)行期間報錯索引長度超過 3072。

Error altering new table `dms_offline`.`_worker_board_quota_counting_new`: DBD::mysql::db do failed: Specified key was too long; max key length is 3072 bytes [for Statement "ALTER TABLE `dms_offline`.`_worker_board_quota_counting_new` modify column `business_id` varchar(1456) NOT NULL COMMENT '業(yè)務(wù)id';"] at /usr/bin/pt-online-schema-change line 9194.

查看表結(jié)構(gòu),顯示字符集為 utf8mb4,索引類型為聯(lián)合唯一索引,business_id 字段長度從 456 擴(kuò)展到 1456。

mysql> show create table dms_offline.worker_board_quota_counting \G
*************************** 1. row ***************************
       Table: worker_board_quota_counting
Create Table: CREATE TABLE `worker_board_quota_counting` (
  `business_id` varchar(456) NOT NULL COMMENT '業(yè)務(wù)id',
  UNIQUE KEY `idx_source_businessid` (`source`,`business_id`),
) ENGINE=InnoDB AUTO_INCREMENT=19747573 DEFAULT CHARSET=utf8mb4 COMMENT='人員看板計提表'
1 row in set (0.00 sec)

查看參數(shù),顯示已開啟 innodb_large_prefix。

mysql> select @@innodb_large_prefix;
+-----------------------+
| @@innodb_large_prefix |
+-----------------------+
|                     1 |
+-----------------------+
1 row in set (0.00 sec)

案例 3

時間:2024-01-22 23:59:12

工單類型:分庫分表

數(shù)據(jù)庫版本:5.7.21 報錯,5.7.24 不報錯

SQL

ALTER TABLE mst_sku
modify `upc_code` varchar(1000) DEFAULT NULL COMMENT '69碼';

日志顯示 pt-osc 執(zhí)行期間報錯索引長度超過 767。

Error altering new table `wms3`.`__mst_sku_new`: DBD::mysql::db do failed: Index column size too large. The maximum column size is 767 bytes. [for Statement "ALTER TABLE `wms3`.`__mst_sku_new` MODIFY COLUMN `upc_code` varchar(1000) DEFAULT NULL COMMENT '69碼';"] at /usr/bin/pt-online-schema-change line 9194.

查看表結(jié)構(gòu),顯示字符集為 utf8,索引類型為單列非唯一索引,upc_code 字段長度從 64 擴(kuò)展到 1000,注意其中行格式為 COMPACT。

mysql> show create table `wms3`.`mst_sku` \G
*************************** 1. row ***************************
       Table: mst_sku
Create Table: CREATE TABLE `mst_sku` (
  `upc_code` varchar(64) DEFAULT NULL COMMENT '69碼',
  KEY `idx_sku_upccode` (`upc_code`),
) ENGINE=InnoDB AUTO_INCREMENT=12952734 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='商品信息表表'
1 row in set (0.00 sec)

查看參數(shù),顯示已開啟 innodb_large_prefix。

mysql> select @@innodb_large_prefix;
+-----------------------+
| @@innodb_large_prefix |
+-----------------------+
|                     1 |
+-----------------------+
1 row in set (0.00 sec)

由于分庫分表工單中只有一個實(shí)例報錯,因此查看每個實(shí)例的數(shù)據(jù)庫版本與執(zhí)行結(jié)果。

ysql> select a.instance_version, t.execute_status from inception_job as t 
inner join assets_instance as a on t.mysql_ip=a.instance_ip 
where t.xbp_id =9334073;
+------------------+----------------+
| instance_version | execute_status |
+------------------+----------------+
| MySQL5.7.24      |              4 |
| MySQL5.7.24      |              4 |
| MySQL5.7.24      |              4 |
| MySQL5.7.24      |              4 |
| MySQL5.7.24      |              4 |
| MySQL5.7.24      |              4 |
| MySQL5.7.24      |              4 |
| MySQL5.7.24      |              4 |
| MySQL5.7.21      |              3 |
+------------------+----------------+
9 rows in set (0.00 sec)

其中:

  • execute_status = 4 表示成功,3 表示失敗;
  • 顯示有一個實(shí)例失敗,版本是 5.7.21,其他實(shí)例都是 5.7.24,都執(zhí)行成功,這一點(diǎn)很反常。

因此盡管上面三個案例都是報錯索引超長,但是其中第三個案例中 5.7.21 報錯的現(xiàn)象比較反常,因此進(jìn)行分析。

分析

索引最大長度

其中對于 InnoDB 存儲引擎,單列索引的最大長度是 767 字節(jié),聯(lián)合索引的最大長度是 3072 字節(jié)。

不同版本的索引最大長度也不同。

其中:

  • 5.5 中引入 innodb_large_prefix 參數(shù),5.5 與 5.6 中該參數(shù)默認(rèn)關(guān)閉,5.7 中默認(rèn)開啟。其中:

參數(shù)關(guān)閉時單列索引的最大長度為 767 字節(jié);

參數(shù)開啟時單列索引的最大長度為 3072 字節(jié)。

  • 8.0 中移除 innodb_large_prefix 參數(shù)。

innodb_large_prefix

參考官方文檔,innodb_large_prefix 參數(shù)用于控制行格式 DYNAMIC or COMPRESSED 中的索引最大長度。

When this option is enabled, index key prefixes longer than 767 bytes (up to 3072 bytes) are allowed for InnoDB tables that use DYNAMIC or COMPRESSED row format.

同時滿足以下三個條件時允許創(chuàng)建 large index(索引最大長度為 3072 字節(jié)):

  • ROW_FORMAT = DYNAMIC or COMPRESSED
  • innodb_file_format = Barracuda
  • innodb_large_prefix = 1

其中有一個條件不滿足時索引最大長度為 767,且超長數(shù)據(jù)將被截斷。

innodb_large_prefix is enabled by default in MySQL 5.7. This change coincides with the default value change for。innodb_file_format, which is set to Barracuda by default in MySQL 5.7. Together, these default value changes allow larger index key prefixes to be created when using DYNAMIC or COMPRESSED row format. If either option is set to a non-default value, index key prefixes larger than 767 bytes are silently truncated.

innodb_large_prefix is deprecated; expect it to be removed in a future release. innodb_large_prefix was introduced to disable large index key prefixes for compatibility with earlier versions of InnoDB that do not support large index key prefixes.

因此對于案例 3,第一個條件不滿足,原因是行格式指定為 COMPACT,因此索引最大長度為 766 字節(jié),那么超長時會報錯嗎?

測試

5.7.24

測試環(huán)境 5.7.24 執(zhí)行報錯,與官方文檔描述一致,因此報錯是正常現(xiàn)象。

mysql> create table _mst_sku_new (
`upc_code` varchar(64) DEFAULT NULL COMMENT '69碼',
KEY `idx_sku_upccode` (`upc_code`)
) ENGINE=InnoDB CHARSET=utf8 ROW_FORMAT=COMPACT;
Query OK, 0 rows affected (0.02 sec)

mysql> alter table `_mst_sku_new` MODIFY COLUMN `upc_code` varchar(1000) DEFAULT NULL;
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes
 
mysql> select version();
+------------+
| version()  |
+------------+
| 5.7.24-log |
+------------+
1 row in set (0.00 sec)

測試環(huán)境 5.7.33 執(zhí)行成功,但是有警告,原因是 sql_mode 為空,表明 sql_mode 的優(yōu)先級高于 ROW_FORMAT。

圖片圖片

線上環(huán)境 5.7.24 執(zhí)行成功,原因是 sql_mode = NO_ENGINE_SUBSTITUTION,因此將報錯降級為警告。

mysql> set session sql_mode='STRICT_TRANS_TABLES';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> alter table `_mst_sku_new` MODIFY COLUMN `upc_code` varchar(1000) DEFAULT NULL;
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

mysql> set session sql_mode='NO_ENGINE_SUBSTITUTION';
Query OK, 0 rows affected (0.00 sec)

mysql> alter table `_mst_sku_new` MODIFY COLUMN `upc_code` varchar(1000) DEFAULT NULL;
Query OK, 0 rows affected, 1 warning (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 1

線上環(huán)境 5.7.21 執(zhí)行失敗,可是同樣 sql_mode = NO_ENGINE_SUBSTITUTION,原因是什么呢?

5.7.21

線上環(huán)境 5.7.21 與 5.7.24 配置相同但是報錯。

mysql> create table _mst_sku_new (
`upc_code` varchar(64) DEFAULT NULL COMMENT '69碼',
KEY `idx_sku_upccode` (`upc_code`)
) ENGINE=InnoDB CHARSET=utf8 ROW_FORMAT=COMPACT;
Query OK, 0 rows affected (0.01 sec)

mysql> select @@sql_mode;
+------------------------+
| @@sql_mode             |
+------------------------+
| NO_ENGINE_SUBSTITUTION |
+------------------------+
1 row in set (0.00 sec)

mysql> alter table `_mst_sku_new` MODIFY COLUMN `upc_code` varchar(1000) DEFAULT NULL;
ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.

mysql> alter table _mst_sku_new ROW_FORMAT=dynamic;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table `_mst_sku_new` MODIFY COLUMN `upc_code` varchar(1000) DEFAULT NULL;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

其中:

  • 報錯不同,Index column size too large. The maximum column size is 767 bytes;
  • ROW_FORMAT = COMPACT 報錯,理論上不報錯,不合理,原因是 sql_mode = NO_ENGINE_SUBSTITUTION;
  • ROW_FORMAT = DYNAMIC 不報錯,理論上不報錯,合理;

因此懷疑 5.7.21 中存在 bug,比如判斷是否支持 create larger index 時沒有判斷 sql_mode。

5.7.23

查看 release notes,顯示 5.7.23 中修復(fù)了一個 bug,bug 的現(xiàn)象是對于 COMPACT 或 REDUNDANT:

  • 嚴(yán)格模式下不報錯
  • 非嚴(yán)格模式下不告警

For attempts to increase the length of a VARCHAR column of an InnoDB table using ALTER TABLE with the INPLACE algorithm, the attempt failed if the column was indexed.

If an index size exceeded the InnoDB limit of 767 bytes for COMPACT or REDUNDANT row format, CREATE TABLE and ALTER TABLE did not report an error (in strict SQL mode) or a warning (in nonstrict mode). (Bug #26848813)

對應(yīng) commit 為 MySQL Commit 913071c,下面表格中展示修復(fù)后的行格式與索引長度,以及嚴(yán)格模式與非嚴(yán)格模式下返回報錯還是告警,其中 IL 表示 Index Limit。

Row Format

INDEX LIMIT

STRICT MODE (>IL)

NON-STRICT MODE (>IL)

Compact/Redundant (Non Unique Index)

767 bytes

Error

Index truncation (767) and warning

Compact/Redundant (Unique/Primary Index)

767 bytes

Error

Error

Dynamic/Compressed (Non Unique Index)

3072 bytes

Error

Index truncation (3072) and warning

Dynamic/Compressed (Unique/Primary Index)

3072 bytes

Error

Error

其中當(dāng)索引超長時,返回報錯還是告警由索引類型與 sql_mode 共同決定:

  • 唯一索引,對于嚴(yán)格模式與非嚴(yán)格模式,均返回報錯;
  • 非唯一索引,對于嚴(yán)格模式,返回報錯,對于非嚴(yán)格模式,返回警告,并將索引值截斷為前綴索引。

因此,判斷該現(xiàn)象對應(yīng)該 bug,表現(xiàn)為 5.7.21 非嚴(yán)格模式中,非唯一索引超長后返回報錯,而不是警告。

debug

debug 數(shù)據(jù)庫版本為 5.7.33,測試索引超長返回警告的堆棧見下圖。

其中有以下兩個函數(shù):

  • mysql_prepare_create_table
  • push_warning_printf

commit 中顯示修改 ha_innobase::max_supported_key_part_length 函數(shù)。

因此給以上三個函數(shù)設(shè)置斷點(diǎn)。

測試顯示行記錄為 COMPACT 時,返回索引最大長度為 767。

圖片圖片

在判斷索引長度超長(1000 * 3 = 3000 > 767)后,判斷返回報錯還是警告。

圖片圖片

其中:

  • 如果是唯一索引,返回報錯;
  • 如果是非唯一索引,繼續(xù)判斷 sq_mode,如果是嚴(yán)格模式,返回報錯,否則返回警告,并且將索引長度自動截斷實(shí)現(xiàn)字節(jié)對齊。變量 key_part_length 從 767 改為 765 字節(jié),對應(yīng) utf8 字符集 255 字符。

相關(guān)代碼如下所示。

// 如果不是唯一索引,也就是二級非唯一索引,根據(jù) sql_mode 判斷是否返回報錯
 if (key->type == KEYTYPE_MULTIPLE)
 {
   /* not a critical problem */
    // 警告
   push_warning_printf(thd, Sql_condition::SL_WARNING,
                              ER_TOO_LONG_KEY, ER(ER_TOO_LONG_KEY),
                              key_part_length);
          /* Align key length to multibyte char boundary */
          // 索引長度自動截斷,比如 767 // 3 = 255
          // 將 key_part_length 減少到最接近的整數(shù)倍數(shù),使得它不超過當(dāng)前字符集中最多的多字節(jié)字符長度
          key_part_length-= key_part_length % sql_field->charset->mbmaxlen;
          /*
            If SQL_MODE is STRICT, then report error, else report warning
            and continue execution.
          */
          // 對于嚴(yán)格模式,將警告升級為錯誤
          if (thd->is_error())
            DBUG_RETURN(true);
 }

其中枚舉類型變量 keytype 的定義如下所示,沒有區(qū)分單列索引與聯(lián)合索引,因此判斷 KEYTYPE_MULTIPLE 表示非唯一索引。

enum keytype {
  KEYTYPE_PRIMARY,
  KEYTYPE_UNIQUE,
  KEYTYPE_MULTIPLE,
  KEYTYPE_FULLTEXT,
  KEYTYPE_SPATIAL,
  KEYTYPE_FOREIGN
};

而在 5.7.21 中,返回的索引最大長度等于 3072,大于當(dāng)前字段的長度 3000,因此判斷結(jié)果是索引不超長。

圖片圖片

而在創(chuàng)建索引的時候還會二次檢查判斷索引長度是否超長。

/* Even though we've defined max_supported_key_part_length, we
 still do our own checking using field_lengths to be absolutely
 sure we don't create too long indexes. */

 error = convert_error_code_to_mysql(
  row_create_index_for_mysql(index, trx, field_lengths, handler),
  flags, NULL);

其中:

  • create_index 函數(shù)中調(diào)用 row_create_index_for_mysql 函數(shù)創(chuàng)建索引;
  • row_create_index_for_mysql 函數(shù)中檢查索引的長度與行格式對應(yīng)的索引最大長度,其中通過宏 DICT_MAX_FIELD_LEN_BY_FORMAT 獲取索引長度;
/* Column or prefix length exceeds maximum column length */
  if (len > (ulint) DICT_MAX_FIELD_LEN_BY_FORMAT(table)) {
   err = DB_TOO_BIG_INDEX_COL;

   dict_mem_index_free(index);
   goto error_handling;
  }
 }
  • DICT_MAX_FIELD_LEN_BY_FORMAT 宏中根據(jù)行格式返回索引最大長度,COMPACT 對應(yīng) 767;
/** Find out maximum indexed column length by its table format.
For ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT, the maximum
field length is REC_ANTELOPE_MAX_INDEX_COL_LEN - 1 (767). For
Barracuda row formats COMPRESSED and DYNAMIC, the length could
be REC_VERSION_56_MAX_INDEX_COL_LEN (3072) bytes */
#define DICT_MAX_FIELD_LEN_BY_FORMAT(table)    \
  ((dict_table_get_format(table) < UNIV_FORMAT_B)  \
   ? (REC_ANTELOPE_MAX_INDEX_COL_LEN - 1)  \
   : REC_VERSION_56_MAX_INDEX_COL_LEN)
  • 由于 3000 > 767,因此判斷索引超長,最終返回報錯;
  • 但是為什么非嚴(yán)格模式下沒有將報錯降級為警告的原因暫時沒查到。

處理

時間:2024-11-24 02:00:27

10個月以后,這套該分庫分表給其他字段擴(kuò)展長度時再次觸發(fā)該問題,因此決定進(jìn)行處理,具體是將數(shù)據(jù)庫從 5.7.21 升級到 5.7.24。

而在升級后發(fā)現(xiàn)兩個現(xiàn)象:

  • 索引中字符長度自動調(diào)整為 255,正常現(xiàn)象;
  • 不小心又踩坑了,先升級的主庫,執(zhí)行 DDL 后導(dǎo)致從庫復(fù)制中斷,異常現(xiàn)象。

如下所示,對比執(zhí)行失敗與執(zhí)行成功時的索引長度。

# 失敗后
KEY `idx_dispatch_no` (`dispatch_no`)

# 成功后
KEY `idx_dispatch_no` (`dispatch_no`(255)),

官方文檔顯示,從 5.7.17 版本開始:

  • 對于非唯一索引,如果是非嚴(yán)格模式,索引超長后返回警告,并自動截斷到支持的索引最大長度;
  • 對于唯一索引,索引超長后直接報錯,不會發(fā)生截斷,原因是截斷后可能導(dǎo)致唯一性約束失效。

As of MySQL 5.7.17, if a specified index prefix exceeds the maximum column data type size, CREATE INDEX handles the index as follows:

For a nonunique index, either an error occurs (if strict SQL mode is enabled), or the index length is reduced to lie within the maximum column data type size and a warning is produced (if strict SQL mode is not enabled).

For a unique index, an error occurs regardless of SQL mode because reducing the index length might enable insertion of nonunique entries that do not meet the specified uniqueness requirement.

如下所示,進(jìn)行測試。

其中:

  • 嚴(yán)格模式,非唯一索引,索引超長后報錯;
  • 非嚴(yán)格模式,非唯一索引,索引超長后警告,并自動截斷;
  • 非嚴(yán)格模式,唯一索引,索引超長后報錯。

主庫升級后使用 pt-osc 執(zhí)行 DDL 導(dǎo)致從庫復(fù)制中斷,原因是從庫未升級。

重試時發(fā)生異常,日志顯示執(zhí)行暫停。

2024-11-25T11:35:07 Copying approximately 764 rows...
Replica MSS-2hbqmzhk2m is stopped. Waiting. 
Killed

查看復(fù)制,顯示復(fù)制中斷,原因是從庫執(zhí)行 DDL 報錯,pt-osc 延遲檢測期間發(fā)現(xiàn)復(fù)制中斷后執(zhí)行暫停。

mysql> SHOW SLAVE STATUS \G
*************************** 1. row ***************************
               Last_SQL_Errno: 1709
               Last_SQL_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction '965c7418-175f-11ee-b6d3-fa163eae0649:12102' at master log mysql-bin.146487, end_log_pos 8137214. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any.
     Last_SQL_Error_Timestamp: 241125 11:35:07
            Executed_Gtid_Set: 965c7418-175f-11ee-b6d3-fa163eae0649:1-12101
                Auto_Position: 1
1 row in set (0.00 sec)

mysql> select * from performance_schema.replication_applier_status_by_worker  limit 1 \G
*************************** 1. row ***************************
         CHANNEL_NAME: 
            WORKER_ID: 1
            THREAD_ID: NULL
        SERVICE_STATE: OFF
LAST_SEEN_TRANSACTION: 965c7418-175f-11ee-b6d3-fa163eae0649:12102
    LAST_ERROR_NUMBER: 1709
   LAST_ERROR_MESSAGE: Worker 1 failed executing transaction '965c7418-175f-11ee-b6d3-fa163eae0649:12102' at master log mysql-bin.146487, end_log_pos 8137214; Error 'Index column size too large. The maximum column size is 767 bytes.' on query. Default database: 'wms3'. Query: 'ALTER TABLE `wms3`.`_task_group_new` MODIFY COLUMN dispatch_no varchar(500) NULL COMMENT '派車單號''
 LAST_ERROR_TIMESTAMP: 2024-11-25 11:35:07
1 row in set (0.01 sec)

知識點(diǎn)

ROW_FORMAT

innodb_default_row_format 參數(shù)用于控制默認(rèn)行格式,取值與版本有關(guān):

  • 5.0.3 版本之前,僅支持一種行格式 REDUNDANT;
  • 5.0.3 - 5.7.8,默認(rèn)行格式為 COMPACT;
  • 從 5.7.9 版本開始,默認(rèn)行格式為 DYNAMIC,包括 8.0。

行格式 COMPACT 與 DYNAMIC 的主要區(qū)別是行溢出(一個列中存儲的數(shù)據(jù)大于等于8098個字節(jié))數(shù)據(jù)的保存方式不同,其中:

  • COMPACT,在記錄的真實(shí)數(shù)據(jù)處存儲字段真實(shí)數(shù)據(jù)的前 768 個字節(jié),剩余數(shù)據(jù)保存在其他頁中,并在真實(shí)數(shù)據(jù)中保存溢出頁地址;
  • DYNAMIC,把所有的字節(jié)都存儲到其他頁面中,只在記錄的真實(shí)數(shù)據(jù)處存儲其他頁面的地址。

圖片圖片

因此在數(shù)據(jù)庫升級過程中也需要關(guān)注行格式。

故障分析 | ERROR 1709: Index column size too large 引發(fā)的思考 文章中分享了一個案例,現(xiàn)象是數(shù)據(jù)庫重啟后有張表無法訪問,SELECT、DML 和 DDL 執(zhí)行均報錯 ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.。

復(fù)現(xiàn)流程如下所示:

  • 數(shù)據(jù)庫從 5.6.21 原地升級到 8.0.21,升級之前創(chuàng)建的一個表未指定行格式,因此使用默認(rèn)行格式 COMPACT;
  • 升級后添加字段并創(chuàng)建索引,索引超長但是沒有報錯,也沒有警告;
  • 數(shù)據(jù)庫重啟前,表可以正常訪問;
  • 數(shù)據(jù)庫重啟后,表無法訪問,報錯索引超長。

最終定位到也是一個 bug,具體表現(xiàn)為非顯式定義的 redundant 行格式表允許創(chuàng)建的索引列大小超 767 bytes,并在 8.0.22 版本中修復(fù)。

因此建議在數(shù)據(jù)庫升級前檢查隱式創(chuàng)建行格式為 compact/redundant 的表,并顯式指定。

相關(guān)案例

下面引申一個話題,SQL 工單中遇到過 goinception 語法校驗(yàn)通過,但是執(zhí)行時報錯行超長的現(xiàn)象,因此分別測試 goinception 是否可以識別字段超長與行超長。

已知:

  • 對于VARCHAR(M)類型的列最多可以占用65535個字節(jié)。其中的M代表該類型最多存儲的字符數(shù)量;
  • MySQL對一條記錄占用的最大存儲空間是有限制的,除了BLOB或者TEXT類型的列之外,其他所有的列(不包括隱藏列和記錄頭信息)占用的字節(jié)長度加起來不能超過65535個字節(jié)。

字段超長

SQL

create table,155355 * 3 > 65535,因此字段長度超長。

create table ttt(
  id int primary key auto_increment comment 'id', 
  a varchar(155355) default '' comment 'a'
) comment 'ttt';

goinception 返回報錯字段超長,建議使用大字段替換 varchar。

Column length too big for column 'a' (max = 21845); use BLOB or TEXT instead. Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs.

add column;

alter table t1 add column aa varchar(155355) default '' comment 'a';

goinception;

Column length too big for column 'aa' (max = 21845); use BLOB or TEXT instead.

modify column;

alter table t1 modify column a varchar(155355) default '' comment 'a';

goinception;

Column length too big for column 'a' (max = 21845); use BLOB or TEXT instead.

因此,測試顯示 goinception 可以驗(yàn)證字段超長,包括建表與改表時,那么是否可以驗(yàn)證行超長?

行超長

create table,15535 * 3 * 2 = 93210 > 65535,因此雖然單個字段不超長,但是行超長。

create table ttt(
  id int primary key auto_increment comment 'id', 
  a varchar(15535) default '' comment 'a',
  b varchar(15535) default '' comment 'b'
) comment 'ttt';

goinception 返回校驗(yàn)通過,當(dāng)然實(shí)際執(zhí)行會失敗。

{
    "id": 1, 
    "stage": "CHECKED", 
    "errlevel": 0, 
    "stagestatus": "Audit Completed", 
    "errormessage": "", 
    "sql": "USE `cctest`", 
    "affected_rows": 0, 
    "sequence": "0_0_00000000", 
    "backup_dbname": "", 
    "execute_time": "0", 
    "sqlsha1": "", 
    "backup_time": "0", 
    "actual_affected_rows": ""
}

因此結(jié)論是 goinception 可以發(fā)現(xiàn)單字段超長,但是無法發(fā)現(xiàn)多字段導(dǎo)致的行超長。

因此,SQL 工單中自定義行超長校驗(yàn),調(diào)用接口返回報錯。

{
    "code": 16, 
    "message": "SQLCheckMaxRowSizeError", 
    "error": "Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs. 庫:cctest,表:ttt,行大小為:93214,超過最大行大小65535字節(jié),請修改字段長度或類型"
}

原因是代碼中自行實(shí)現(xiàn)行超長檢測,并自定義異常類。

class SQLCheckMaxRowSizeError(BaseError):  
    def __init__(self, db_name="", table="", row_size=""):  
        BaseError.__init__(  
            self, code=SQL_Check_MAX_ROW_SIZE_Error, message="SQLCheckMaxRowSizeError",  
            error="Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. "  
                  "This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs."                  " 庫:%s,表:%s,行大小為:%s,超過最大行大小65535字節(jié),請修改字段長度或類型" % (db_name, table, row_size)  
        )

結(jié)論

MySQL 5.5 中引入 innodb_large_prefix 參數(shù),5.5 與 5.6 中該參數(shù)默認(rèn)關(guān)閉,5.7 中默認(rèn)開啟。

innodb_large_prefix 參數(shù)用于控制行格式  DYNAMIC or COMPRESSED 中的索引最大長度。

5.7 中同時滿足以下三個條件時索引最大長度為 3072 字節(jié):

  • ROW_FORMAT = DYNAMIC or COMPRESSED
  • innodb_file_format = Barracuda
  • innodb_large_prefix = 1

其中有一個條件不滿足時索引最大長度等于 767 字節(jié)。因此對于行格式 COMPACT,索引最大長度為 767 字節(jié)。

當(dāng)索引超長時,返回報錯還是告警由索引類型與 sql_mode 共同決定:

  • 唯一索引,對于嚴(yán)格模式與非嚴(yán)格模式,均返回報錯,注意不允許截斷,否則可能導(dǎo)致索引失效;
  • 非唯一索引,對于嚴(yán)格模式,返回報錯,對于非嚴(yán)格模式,返回警告,并將索引值截斷為前綴索引。

而本文中 5.7.21 版本中的現(xiàn)象與上述描述不符,非嚴(yán)格模式中,非唯一索引超長后返回報錯,而不是警告。因此判斷該現(xiàn)象是 bug。

分析代碼后發(fā)現(xiàn),有兩次索引長度檢查,但是索引最大長度的判斷條件不一致:

  • 第一次,索引最大長度由 innodb_large_prefix 決定,參數(shù)開啟時返回 3072;
  • 第二次,索引最大長度由行格式?jīng)Q定,COMPACT 對應(yīng) 767。

因此在 5.7.21 中當(dāng) COMPACT 開啟 innodb_large_prefix 時,將導(dǎo)致第一次檢查通過,第二次檢查報錯,但是具體為什么沒有將報錯降級為警告的原因暫未查到。

而在 8.0 中移除了 innodb_large_prefix 參數(shù),索引最大長度統(tǒng)一由行格式?jīng)Q定,這樣也就避免了該問題。

回過頭來分析最初的三個案例,其中:

  • 案例 1,5.6.39,隱式 COMPACT,單列唯一索引報錯超長 767,報錯正常;
  • 案例 2,5.7.33,隱式 COMPACT,聯(lián)合唯一索引報錯超長 3072,報錯正常;
  • 案例 3,5.7.21,顯式 COMPACT,單列非唯一索引報錯超長 767,報錯不正常,正常應(yīng)該是警告。

注意都是非嚴(yán)格模式。

責(zé)任編輯:武曉燕 來源: 丹柿小院
相關(guān)推薦

2009-12-11 14:16:13

PHP獲取字段長度

2010-11-22 11:55:23

MySQL字段

2010-11-01 14:30:47

db2擴(kuò)充表空間

2010-10-08 14:59:00

MySql字段

2024-01-07 20:05:33

2014-04-15 11:22:24

2023-12-25 14:47:14

2024-04-15 10:30:22

MySQL存儲引擎

2023-11-13 10:55:09

MySQL數(shù)據(jù)庫

2023-04-10 08:28:35

CharVarchar

2024-05-31 09:31:00

2010-04-23 16:18:36

Oracle存取

2023-02-07 09:01:30

字符串類型MySQL

2010-09-25 10:48:59

SQL字段類型長度

2022-12-05 14:05:26

MySQL最大取值存儲

2010-08-16 13:25:41

DB2數(shù)據(jù)庫操作

2016-09-20 23:44:43

2024-03-14 08:11:45

模型RoPELlama

2024-07-15 08:32:34

2019-06-18 15:20:01

MySQL連接錯誤數(shù)據(jù)庫
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

欧美日韩性视频在线| 日本系列欧美系列| 欧美精品一区二区三区久久久| 福利视频一区二区三区四区| 色资源在线观看| 久久激情五月激情| 久久久久在线观看| 国产7777777| 18国产精品| 91国产免费看| 日韩小视频网站| 阿v免费在线观看| 成人免费不卡视频| 国产精品视频一区国模私拍| 毛片a片免费观看| 国产亚洲一卡2卡3卡4卡新区| 欧美一级搡bbbb搡bbbb| 欧美日韩激情视频在线观看| 免费在线看黄网站| 久久综合九色综合欧美98| 成人精品久久一区二区三区| 日本一区二区三区精品| 欧美在线网站| 色黄久久久久久| 好吊视频在线观看| 激情小说亚洲色图| 日韩一区二区在线观看视频| 麻豆三级在线观看| 高潮一区二区| 精品久久久久久久久久ntr影视| 手机在线视频你懂的| 国产大学生校花援交在线播放| 不卡一区二区三区四区| 97se国产在线视频| 亚洲一区二区天堂| 日本一不卡视频| 国产精品com| 欧美在线观看不卡| 亚洲国产日本| 欧美黑人一区二区三区| 欧美第一页在线观看| 欧美1级片网站| 色诱女教师一区二区三区| av网站免费在线看| 国产99精品一区| 亚洲欧美日韩视频一区| 亚洲狠狠婷婷综合久久久久图片| 精品按摩偷拍| 亚洲大胆人体在线| 性囗交免费视频观看| 国产成人一二片| 精品国产3级a| 星空大象在线观看免费播放| 成人三级av在线| 亚洲成人精品在线| 性欧美成人播放77777| 日韩电影不卡一区| 日韩精品一区二区三区第95| 人妻丰满熟妇av无码久久洗澡| 大型av综合网站| 亚洲国产一区自拍| 丰满少妇一区二区三区| 亚洲欧美日本伦理| 一本一本久久a久久精品牛牛影视| 国产精品成人无码免费| 久久激情电影| 麻豆一区二区在线观看| 欧美卡一卡二卡三| 亚洲国产网站| 国产z一区二区三区| 国产一级片一区二区| 精品一区二区综合| 999热视频在线观看| 免费看av毛片| 久久综合网色—综合色88| 日本视频精品一区| 成人免费网址| 欧美日韩国产精品| 欧美 日韩 国产 激情| 久久er热在这里只有精品66| 欧美一区二区视频在线观看2022| 第一页在线视频| 亚洲va久久久噜噜噜久久| 亚洲色图日韩av| 少妇高潮在线观看| 在线欧美亚洲| 国产精品一区二区久久久久| 精品国产区一区二| 久久综合久久鬼色| 经典三级在线视频| 中文不卡1区2区3区| 欧美日韩视频专区在线播放| 日本黄色三级网站| 夜色77av精品影院| 美女精品视频一区| 色老头在线视频| 国产乱子轮精品视频| 噜噜噜噜噜久久久久久91| 91九色在线porn| 亚洲成国产人片在线观看| 天天爽人人爽夜夜爽| 99精品中文字幕在线不卡 | 国产精品一区二区三区av麻| 一夜七次郎国产精品亚洲| 黄色一级免费视频| 日韩黄色小视频| 国产精品美女久久久久av福利| 国产三级视频在线| 午夜精品一区二区三区免费视频| 日本xxxx黄色| 天天躁日日躁狠狠躁欧美巨大小说| 综合网日日天干夜夜久久| 日本中文字幕免费观看| 激情偷乱视频一区二区三区| 欧美日韩视频在线一区二区观看视频| 久久bbxx| 欧美三级日韩三级国产三级| 亚洲国产精品成人综合久久久| 婷婷久久一区| 国产精品jvid在线观看蜜臀| 天天综合天天色| 一区二区三区四区国产精品| 三级视频中文字幕| 亚洲日本三级| 韩国福利视频一区| 精品人妻无码一区二区| 国产精品嫩草久久久久| 国产亚洲天堂网| 风间由美一区二区av101| 久热精品视频在线| 91麻豆成人精品国产| 国产亚洲精品资源在线26u| 欧美二区在线视频| 好吊妞视频这里有精品| 欧美成人合集magnet| 亚洲综合免费视频| 国产精品人妖ts系列视频| 国产精品无码av无码| 人人网欧美视频| 久久免费成人精品视频| 蜜臀av在线观看| 一区二区三区成人在线视频| www.偷拍.com| 欧美阿v一级看视频| 亚洲最大的免费| 超碰在线免费公开| 欧美一区二区三区影视| 欧美日韩精品在线观看视频| 国产a精品视频| 天堂8在线天堂资源bt| japanese色系久久精品| 欧美激情小视频| 日本激情一区二区三区| 性欧美疯狂xxxxbbbb| www.88av| 久久久久国产精品一区二区| 亚洲春色在线| 亚洲综合资源| 欧美日韩国产成人在线| 欧美 日韩 人妻 高清 中文| 欧美日韩国产精品| 国产精久久一区二区三区| 免费在线观看不卡| 182在线视频观看| 91精品国产黑色紧身裤美女| 一级片黄色录像| 久久av资源站| 国产成人免费高清视频| 视频国产精品| 久久久久中文字幕| 青青免费在线视频| 精品视频一区二区三区免费| 二区三区四区视频| 国产成人免费视频网站高清观看视频| 欧美黄网在线观看| 久久99成人| 97久久国产精品| 国产污视频在线| 欧美高清你懂得| 久久一二三四区| 久久毛片高清国产| 911福利视频| 在线日韩视频| 免费观看国产视频在线| 一级片免费在线播放| 国产欧美视频一区二区三区| jizz欧美性11| 亚洲午夜黄色| 日韩影院一区| 亚洲精品一区二区三区在线| 欧美制服第一页| 理论片午午伦夜理片在线播放| 欧美大片在线观看| 欧美一区二区三区久久久| 亚洲视频一二区| 丝袜美腿中文字幕| 国产制服丝袜一区| 国模无码视频一区二区三区| 国产精品福利在线观看播放| 国产伦精品一区二区三区免| 久久精品黄色| 91精品国产高清自在线| 麻豆av免费在线观看| 国产视频精品在线| 国产ts人妖调教重口男| 在线免费观看日本欧美| 日本少妇性生活| 中文字幕亚洲视频| 老牛影视av老牛影视av| 福利一区二区在线观看| 九九精品久久久| 久久狠狠一本精品综合网| 天堂av在线中文| 欧美色图一区| 欧美中日韩免费视频| 国产精品1luya在线播放| 成人性教育视频在线观看| 777午夜精品电影免费看| 国内外成人免费激情在线视频| www久久日com| 精品国产一区二区三区久久| 可以直接在线观看的av| 亚洲成人a**站| 99精品免费观看| 欧美日韩成人一区| 国产女主播喷水视频在线观看| 午夜视频在线观看一区二区三区| 糖心vlog免费在线观看| 国产精品色眯眯| 日本成人免费视频| 久久久精品蜜桃| 搡老熟女老女人一区二区| 不卡av在线免费观看| 欧美色图校园春色| 国产一区二区三区四| caoporm在线视频| 久久99久久精品欧美| 亚洲高清在线免费观看| 视频在线在亚洲| 日韩 欧美 高清| 丝袜亚洲精品中文字幕一区| 免费在线激情视频| 亚洲资源av| 国产主播在线看| 日韩影院在线观看| 国产成人精品视频ⅴa片软件竹菊| 亚洲一区欧美激情| 国模杨依粉嫩蝴蝶150p| 日韩在线一二三区| 五月婷婷狠狠操| 捆绑调教美女网站视频一区| 网站一区二区三区| 久久精品999| 九九九九九伊人| 国产成人在线网站| av2014天堂网| 久久老女人爱爱| 亚洲色图第四色| 亚洲欧美日韩系列| 国产精品成人网站| 狠狠躁夜夜躁人人爽天天天天97| www欧美在线| 在线免费观看成人短视频| 亚洲一级av毛片| 91麻豆精品国产91久久久更新时间| 日本一道在线观看| 91p九色成人| 国产日韩精品电影| 欧美中文高清| 久久久久久久久四区三区| 久久99高清| 在线观看欧美一区| 欧美日韩一区自拍 | 久久国产精品亚洲人一区二区三区 | 久久精品高清| 中文字幕乱码免费| 一区二区三区国产在线| 精品www久久久久奶水| 久久精品国产99| 又色又爽又黄18网站| 99精品一区二区| 日本免费www| 亚洲一区二区三区四区五区中文| 国产精品999在线观看| 欧美性色欧美a在线播放| 国产高清免费观看| 亚洲人精品午夜在线观看| 黄色在线免费网站| 777午夜精品福利在线观看| 九七影院97影院理论片久久| 国产精品美女久久久久av福利| 国产一区二区在线| 老司机激情视频| 久久综合图片| wwwxxx色| 中文字幕第一区| 国产特黄大片aaaa毛片| 欧美日韩在线播| 色婷婷av一区二区三| 亚洲人成电影在线观看天堂色| 成年人网站在线| 国产精品成人国产乱一区| 亚洲成av人片在线观看www| 日本不卡一区二区三区视频| 在线一区电影| 少妇网站在线观看| 91在线云播放| 久久婷婷综合国产| 欧美日韩综合色| 看电影就来5566av视频在线播放| 欧美精品一区二区三区国产精品| 欧美特大特白屁股xxxx| 国产99午夜精品一区二区三区| 日韩理论电影| 国产无套粉嫩白浆内谢的出处| 成人动漫一区二区三区| 久久久精品少妇| 欧美最猛黑人xxxxx猛交| 午夜视频www| 欧美极品欧美精品欧美视频| 久久精品 人人爱| 亚洲ai欧洲av| 日日欢夜夜爽一区| 亚州av综合色区无码一区| 亚洲精品少妇30p| 国产一区二区在线播放视频| 一区二区欧美日韩视频| 深夜成人影院| 欧美精品v日韩精品v国产精品| 樱桃成人精品视频在线播放| 成人三级做爰av| 亚洲欧美欧美一区二区三区| 888奇米影视| www国产精品视频| 欧美一级做a| 一区二区三区四区五区精品| 日本在线播放一区二区三区| 男人的天堂官网| 在线亚洲精品福利网址导航| 国产特黄在线| 国产精品青草久久久久福利99| 国产精品嫩模av在线| 欧美综合在线观看视频| 久久久久久毛片| 无码人妻久久一区二区三区 | 亚洲a v网站| 91国产免费看| 日本在线播放| 亚洲va欧美va国产综合久久| 亚洲欧美综合国产精品一区| 在线观看你懂的视频| 亚洲综合成人在线视频| 成人毛片在线免费观看| 国产69精品久久久久9| 精品人人人人| www.日日操| 亚洲欧洲日韩女同| 亚洲精品国产手机| 性色av一区二区三区| 日韩大片在线免费观看| 手机看片福利日韩| 国产精品国产a级| 精品人妻aV中文字幕乱码色欲| 欧美极品少妇xxxxx| 日韩人体视频| 九一精品在线观看| 亚洲人成网站在线| 人妻无码中文字幕| 日韩暖暖在线视频| 欧美超碰在线| 蜜臀视频在线观看| 欧美日韩中文字幕在线| 在线a人片免费观看视频| 91成人免费看| 国产欧美午夜| 99久久久无码国产精品不卡| 91精品在线观看入口| 蜜臀久久精品| 中文字幕久精品免| 成人国产一区二区三区精品| 日韩手机在线视频| 久久综合免费视频影院| 亚洲va久久| 国产亚洲色婷婷久久| 欧美午夜激情在线| 黄色网页在线免费观看| 国产伦精品一区二区三区视频免费 | 国产精品水嫩水嫩| 黄色a在线观看| 国产免费观看久久黄| 亚洲大胆av| 国产中文字幕久久| 日韩av在线一区| 日韩亚洲国产免费| 欧美极品欧美精品欧美| 亚洲视频1区2区| 欧美视频综合| 成人免费看片网址| 久久电影网站中文字幕| 伊人手机在线视频|