精品欧美一区二区三区在线观看 _久久久久国色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ù)棧公眾號

国产欧美中文字幕| 一区二区在线观看免费| 国产97色在线| 久久爱一区二区| 精品一区二区三区四区五区| 午夜精品成人在线| 视频一区国产精品| 亚洲精品一区二区三区区别| 老司机午夜免费精品视频| 亚洲免费高清视频| 久久久精品视频国产| 中文字幕在线直播| 亚洲女人小视频在线观看| 久久国产日韩欧美| 国产乱人乱偷精品视频a人人澡| 精品91久久久久| 国产一区二区三区18| 99免费观看视频| 国产69精品久久久久按摩| 亚洲一区二区五区| 亚洲精品一区二区三区蜜桃久| 国内精品偷拍视频| 日本亚洲三级在线| 91大神在线播放精品| 操她视频在线观看| 男男gay无套免费视频欧美| 日韩一区二区电影网| 成人在线观看a| av影院在线| 中文字幕一区二区三区色视频| 久久人人九九| 亚洲国产剧情在线观看| 久久99久久99精品免视看婷婷| 91国偷自产一区二区三区的观看方式 | 免费影视亚洲| 日韩一区在线免费观看| 欧美主播一区二区三区美女 久久精品人| 国产女主播福利| 麻豆精品视频在线观看免费| 日本三级久久久| 国产微拍精品一区| 亚洲激情婷婷| 色与欲影视天天看综合网| 最新av电影网站| 日韩国产一区二区三区| 国产午夜精品免费一区二区三区 | 亚洲精品国产精品乱码不卡| 精品一区二区三区久久| 国产精品亚洲一区二区三区| 波多野结衣爱爱| 米奇777在线欧美播放| 91精品国产沙发| 亚洲免费在线观看av| 影音先锋亚洲一区| 国内精品美女av在线播放| 久久久久久久久久91| 欧美三级不卡| 欧美日本啪啪无遮挡网站| 97成人资源站| 欧美日本二区| 久久久久久伊人| 日韩精品手机在线| 国产精品久久久一区二区| 91av视频在线观看| 青青视频在线免费观看| 视频一区中文字幕国产| 国产精品成人aaaaa网站| 日韩欧美在线观看免费| 日韩精品一二三| 国产日韩欧美另类| 性中国xxx极品hd| 成人免费毛片aaaaa**| 精品国产一区二区三| 欧美日韩国产综合视频| 中文字幕不卡三区| 在线观看免费黄色片| 免费在线观看的电影网站| 午夜电影久久久| 少妇高清精品毛片在线视频| 成人全视频在线观看在线播放高清 | 97aⅴ精品视频一二三区| 开心色怡人综合网站| 成人精品一区| 尤物av一区二区| 欧美色图另类小说| 久久女人天堂| 欧美成人伊人久久综合网| 给我免费观看片在线电影的| 精品久久久久久久| 久久精品小视频| 日韩xxx高潮hd| 青草av.久久免费一区| 亚洲iv一区二区三区| 日批视频在线播放| 中文字幕成人av| 国产美女在线一区| 九色成人搞黄网站| 精品裸体舞一区二区三区| 国产呦小j女精品视频| 水蜜桃精品av一区二区| 久久久噜噜噜久久中文字免| 超碰在线97观看| 粉嫩蜜臀av国产精品网站| 五月天综合网| 91www在线| 91精品福利在线一区二区三区| 熟女丰满老熟女熟妇| 999视频精品| 91av网站在线播放| 国产三级小视频| 久久精品日产第一区二区三区高清版 | 久久av色综合| 欧美日韩精品欧美日韩精品 | 国产精品三级久久久久三级| 欧美久久久久久久久久久久久久| 成人福利片在线| 亚洲精品白浆高清久久久久久| 成人信息集中地| 久久激情一区| 国产精品av一区| 国产成人无吗| 在线免费观看一区| 国产草草浮力影院| 欧美激情第8页| 国产欧美一区二区三区视频| 国产女主播在线直播| 亚洲大片精品永久免费| 欧美视频国产视频| 成人综合专区| 国产成人免费av| 四虎在线观看| 精品久久久久久久久中文字幕 | 成人福利一区| 欧美日本黄视频| 99热这里只有精品99| 国产精品区一区二区三区| 国产熟女高潮视频| 加勒比色老久久爱综合网| 色综合久久精品亚洲国产| 91女人18毛片水多国产| 国产精品午夜电影| 一区二区三区国产免费| 欧美丝袜一区| 国产精品久久精品| 成年人在线观看视频| 色综合久久久久久久久久久| 手机在线看片日韩| 在线亚洲精品| 农村寡妇一区二区三区| 午夜激情在线播放| 亚洲区一区二区| 国产免费www| 国产精品理论在线观看| 中国黄色片免费看| 99久久国产综合精品成人影院| 国产精品久久久久免费a∨| 国产原创av在线| 欧美吞精做爰啪啪高潮| 99成人在线观看| 国产在线精品不卡| 国产美女作爱全过程免费视频| 99精品国产一区二区三区2021| 欧美精品videofree1080p| 女人18毛片水真多18精品| 亚洲1区2区3区视频| 无码精品一区二区三区在线播放| 欧美亚洲一区二区三区| 日韩精品电影网站| 黄页免费欧美| 色综合久久中文字幕综合网小说| 亚洲AV无码一区二区三区少妇| 亚洲国产精品久久人人爱| 青青草视频播放| 日本vs亚洲vs韩国一区三区二区 | 91精品国产一区二区三区| 久草中文在线视频| av一区二区三区四区| 国产免费人做人爱午夜视频| 日韩精品一卡| 国产98在线|日韩| 一区二区三区电影大全| 正在播放亚洲1区| 99国产成人精品| 欧美性videos高清精品| 国产视频三区四区| 国产精品18久久久久久久网站| 亚欧无线一线二线三线区别| 视频在线不卡免费观看| 国产精品一区免费观看| 精品3atv在线视频| 色中色综合影院手机版在线观看| 免费a级毛片在线观看| 4438x亚洲最大成人网| 美日韩一二三区| 亚洲人成人一区二区在线观看| 一二三不卡视频| 韩国毛片一区二区三区| av免费观看网| 久久精品一区二区不卡| 久久精品一区二区三区不卡免费视频 | 一区二区三区国产精华| 欧美日韩国产高清视频| 国产一区一区| 国产精品久久久久久久久借妻| 乱插在线www| 久久久成人av| 经典三级在线| 亚洲高清在线观看| 国产又大又粗又长| 欧美性xxxx极品高清hd直播| 日韩欧美123区| 日本一区二区免费在线观看视频| 日本精品一二三| 久久er精品视频| 国产一区视频免费观看| 亚洲精品男同| 日韩精品第1页| 日韩激情一区| 日本一区二区三区视频在线播放| 国产精品调教视频| 91亚洲国产成人久久精品网站| av在线一区不卡| 日本不卡视频在线播放| av影片在线| 欧美激情在线一区| 在线中文字幕电影| www欧美日韩| 国产专区在线| 亚洲女人被黑人巨大进入| 女人18毛片一区二区三区| 在线电影院国产精品| 探花国产精品一区二区| 精品日韩美女的视频高清| 国产亚洲欧美久久久久| 亚洲免费观看高清在线观看| 日韩精品一区二区亚洲av性色| 国产日韩欧美在线一区| 中文幕无线码中文字蜜桃| 99在线视频精品| 星空大象在线观看免费播放| 国产91高潮流白浆在线麻豆| 免费人成视频在线播放| 激情国产一区二区| 日本黄色的视频| 久久精品国产精品青草| av亚洲天堂网| 精品一区二区免费在线观看| 日韩欧美亚洲另类| 精品亚洲成av人在线观看| 尤物国产在线观看| 久久99精品一区二区三区| 日韩欧美国产片| 久久爱www久久做| 一卡二卡三卡四卡五卡| 国产成人av网站| 久久人妻少妇嫩草av蜜桃| 成人在线视频一区| 一本加勒比波多野结衣| xnxx国产精品| 69xxx免费| 成人免费小视频| 欧美又粗又大又长| 香蕉影视欧美成人| 手机av免费观看| 欧美日韩一级视频| 99国产精品99| 亚洲精品久久久久久久久久久久| 欧美女优在线观看| 中文字幕国产亚洲| av片在线观看| 国内精品中文字幕| 搜成人激情视频| 成人综合网网址| 国产精品丝袜在线播放| 日韩精品福利视频| 欧美激情五月| www.玖玖玖| 美女在线视频一区| 台湾佬美性中文| 久久久久久黄色| 欧洲第一无人区观看| 午夜电影久久久| 中文天堂在线视频| 精品三级av在线| 国模吧精品人体gogo| 欧美大奶子在线| 老司机2019福利精品视频导航| 国产欧美日韩中文字幕在线| 91精品入口| 神马影院午夜我不卡影院| 中文字幕一区二区三区在线视频 | 中文字幕一区二区人妻视频| 欧美卡1卡2卡| 色中色在线视频| 欧美成年人网站| 自拍偷自拍亚洲精品被多人伦好爽| 成人av在线亚洲| 日韩福利视频一区| 桥本有菜av在线| 国产精品久久久久毛片大屁完整版 | 日韩电影在线观看一区二区| 日韩午夜激情免费电影| 国产一区二区三区福利| 欧美丰满少妇xxxxx做受| 婷婷激情一区| 国产一区精品在线| 国产精品精品国产一区二区| 岳毛多又紧做起爽| 国产成人在线视频免费播放| gv天堂gv无码男同在线观看| 精品久久久香蕉免费精品视频| 国产一区二区三区视频免费观看| 精品视频偷偷看在线观看| 图片区小说区亚洲| 国产精品偷伦视频免费观看国产| 日韩精品导航| 国产91沈先生在线播放| 久久精品国产免费| 美女100%露胸无遮挡| 婷婷开心激情综合| 韩国av免费在线| 欧美成人精品激情在线观看 | 后进极品白嫩翘臀在线播放| 国产啪精品视频| 精品欧美久久| 黑人糟蹋人妻hd中文字幕| 国产成人精品亚洲日本在线桃色 | 姝姝窝人体www聚色窝| 日韩在线视频一区| 免费观看成人性生生活片 | 第一sis亚洲原创| 欧美在线观看成人| 成人精品亚洲人成在线| 亚洲欧美小视频| 9191国产精品| 免费日本一区二区三区视频| 国产精品一区电影| 中文字幕一区二区三区人妻四季 | 在线视频91p| 国产精品美女网站| 欧美日韩国产免费观看视频| 日本黄网站免费| 久久久午夜精品理论片中文字幕| 日本道在线观看| 日韩麻豆第一页| 日韩精品专区| 色播五月综合| 老司机精品视频一区二区三区| gv天堂gv无码男同在线观看 | 性做久久久久久久久久| 欧美另类交人妖| 国产精品22p| www.av中文字幕| 久久亚洲捆绑美女| 波多野结衣一本一道| 这里只有精品在线观看| 激情久久99| 99视频精品全部免费看| 高清成人在线观看| 四虎成人永久免费视频| 亚洲人成免费电影| 国产极品嫩模在线观看91精品| 色乱码一区二区三区熟女| 国产精品一区不卡| 国产午夜久久久| 国产视频久久久久| 日韩毛片在线| 欧美 日韩 国产 在线观看| 国产成人综合精品三级| 午夜影院在线看| 亚洲网在线观看| 国产精品中文| 国产v片免费观看| 国产三区在线成人av| 91亚洲国产成人久久精品麻豆 | 欧美男女交配| 亚洲人一区二区| 成人一区二区三区在线观看| 精品国产一区二区三区四| 久久精品久久久久久国产 免费| 一区二区视频| 欧美激情精品久久久久久小说| 亚洲天堂2014| 少妇性bbb搡bbb爽爽爽欧美| 国产精品网址在线| 国产精品vip| a级大片在线观看| 欧美一卡2卡3卡4卡| gay欧美网站| avove在线观看| 2014亚洲片线观看视频免费| 91丨porny丨在线中文 | 中文在线播放一区二区| 菠萝菠萝蜜网站| 91精品国产综合久久精品| h片在线观看视频免费| 亚洲一区二区三区午夜| 成人黄色在线网站| 91精东传媒理伦片在线观看| 91sa在线看|