CloudNativeEra
  • Introduction
  • 名词解释
  • Computer Science
    • Computer Organization
      • CPU
      • 二进制、电路、加法器、乘法器
      • 编译、链接、装载
      • 存储器
      • IO
    • Operating System
      • 操作系统基础知识
      • 系统初始化
      • 进程管理
      • Everything about Memory
      • 文件系统
      • 并行编程
      • Linux
        • CPU
        • IO 多路复用
        • DMA IO and Linux Zero Copy
    • Computer Network
      • 网络相关命令
      • 评估系统的网络性能
      • 网络抓包
      • Linux 最多支撑的 TCP 连接
      • 网络虚拟化
      • DHCP 工作原理
    • Data Structure and Algorithm
      • 题目列表
      • Summarize
        • 方法总结
        • 二分思想
        • 树的演化
        • 算法思想总结
      • Data Structure
        • Data Struct - Array
        • Tree
        • Heap
        • Hash
        • 字符串
      • Algorithm
        • Sorting Algorithm
        • 查找
        • 贪心算法
        • 动态规划
        • 位运算
      • Practice Topics
        • Data Struct in SDK
        • Topic - Tree
        • Topic - Graph
        • Topic - 滑动窗口
        • 剑指 Offer 题解
    • 并发编程
      • 并发模式
      • 并发模型
  • 系统设计
    • 软件设计
      • 软件架构
      • 编程范式
      • 系统设计题
      • 设计原则
      • 计算机程序的构造和解释 SICP
    • 领域驱动设计
      • 应用:在线请假考勤管理
      • 应用: library
    • 微服务与云原生
      • Designing and deploying microservices
      • 容器技术
      • Docker
      • Etcd
      • Kubernetes
        • Kubernetes - Mapping External Services
      • Istio
      • 监控
    • 分布式系统
      • 分布式理论
      • 分布式事务
    • 后端存储设计
      • 缓存设计
      • 数据库架构设计
    • CI/CD
    • 设计最佳实践
    • 测试
    • 安全
    • 综合
      • 开发实践
      • 分布式锁
      • 分布式计数服务
      • 弹幕系统设计
      • 消息队列设计
      • 分布式ID生成算法
      • 限流设计
      • 网关设计
      • 通用的幂等设计
      • 分布式任务调度
        • Timer
        • ScheduledExecutorService
        • Spring Task
        • Quartz
      • 交易系统
      • 权限设计
  • 编程语言
    • 编程语言
    • C & C++
    • Java
      • JVM
        • JVM Bytecode
      • Java 核心技术
      • Java 8 新特性
      • Java 集合框架
      • Java NIO
      • 并发编程
        • 线程生命周期与线程中断
        • 三个线程交替打印
        • 两个线程交替打印奇偶
        • 优雅终止线程
        • 等待通知机制
        • 万能钥匙:管程
        • 限流器
        • 无锁方案 CAS
    • Java 源码阅读
      • Unsafe
      • 异步计算 Future
      • Java Queue
      • CoalescingRingBuffer 分析
      • Java Collections
        • PriorityQueue 分析
        • HashMap 分析
        • TreeMap
    • Golang
    • Python
  • 框架/组件/类库
    • Guava
      • Guava Cache
      • Guava EventBus
    • RxJava
    • Apache MINA
    • Netty
      • 网络 IO 模型
      • Netty 生产问题
    • Apache Tomcat
    • MyBatis
    • 限流框架
    • Spring Framework
      • Spring Core
      • Spring 事务管理
    • Spring Boot
    • Spring Cloud
      • Feign & OpenFeign
      • Ribbon
      • Eurake
      • Spring Cloud Config
    • FixJ
    • Metrics
    • Vert.x
  • 中间件
    • Redis
      • Redis 基础
        • Redis 数据结构设计与实现
        • Redis 高性能网络模型
      • Redis checklist
      • 应用案例 - Redis 数据结构
      • 应用案例 - Redis 缓存应用
      • 应用案例 - Redis 集群
      • Redis 客户端
      • Redis 生产案例
        • [译] 在 Redis 中存储数亿个简单键值对
    • MySQL
      • MySQL 基础
      • MySQL Index
      • MySQL Transaction
      • MySQL 优化
      • MySQL 内核
      • MySQL Command
      • MySQL Checklist
      • MySQL Analysis Tool
      • 实现 MySQL
    • State Machine
    • 数据库连接池
    • MQ
      • 高性能内存队列 Disruptor
      • Kafka
      • Pulsar
      • RocketMQ
        • Broker 的设计与实现
      • NSQ
  • 实际案例
    • 线上 Case
      • Request Aborted
      • MySQL - Specified key was too long
      • Java 应用 CPU 100% 排查优化
      • 频繁 GC 导致的 Java 服务不响应
      • 导出优化
  • 大数据
    • 流计算
    • Flink
  • 其他
    • 工具
    • 读书
      • 设计数据密集型应用
      • 实现领域驱动设计
      • 精通比特币
      • 提问的智慧
    • 论文
    • 工程博客
    • 阅读源码
    • 面试
      • 如何在最短的时间里对对方有个全面的了解
    • 分享
    • 软技能
    • Todo
  • Blog
    • #算法
      • 查找
      • 位运算
      • 树
    • #架构
      • 1- 通信
    • Design & Dev & Opt
      • High Performance Data structure Design
  • Tiny Project
    • A Simple WeChat-like Instant Messaging Platform
由 GitBook 提供支持
在本页
  • 现象描述
  • 排错
  • 原理分析
  • 参考链接

这有帮助吗?

  1. 实际案例
  2. 线上 Case

MySQL - Specified key was too long

现象描述

在更新 Prod 环境的数据库时,运行了一个 alter table 语句,MySQL 报错:1071 - Specified key was too long; max key length is 767 bytes , 经过排查数据里的数据、字段和索引,并没有发现太明显的异常。

从错误信息来看,和索引是有关系的;但是本地数据库、test 环境数据库、uat 环境数据库都是正常的,只有 Prod 是有问题的;进过查询资料,定位到一个 MySQL 的配置参数可能和这个问题有关系

排错

在每个环境中查询 MySQL 参数:innodb_large_prefix

-- Test
show variables like 'innodb_large_prefix';
-- result: ON

-- UAT
show variables like 'innodb_large_prefix';
-- result: ON

-- Prod
show variables like 'innodb_large_prefix';
-- Result: OFF

可见不同环境的配置是不一样,这个参数的作用是控制单列索引的最大长度的

  • 对于 Innodb 存储引擎,innodb_large_prefix = OFF 时最大的单列索引长度是 767 Bytes,这里要注意是字节,我们在指定列的类型时一般是 char 或者 varchar,在 utf8 编码下,一个字符 3 Bytes,在 utf8mb4 编码下,一个字符是 4 bytes

  • 对于 MyISAM 存储引擎,单列索引的最大长度是 1000 Bytes

而在我们自己的表定义中,有一个 uniqueId varchar(200) 的字段被用作了索引,而且编码是 utf8mb4,那么索引的理论长度是 800,超过了 767 Bytes。在 Prod 环境中发生这个问题,可能的原因:

  1. innodb_large_prefix 以前是 ON 的,但后来被改成了 OFF,这样就会导致再次修改表结构时报错,增删改查数据不受影响

  2. 其他原因暂时想不到了

原理分析

已知结论:

  1. 对于 Innodb 存储引擎,当 innodb_large_prefix = OFF 时,单列索引的最大长度时 767 Bytes;当 innodb_large_prefix = ON 时,单列索引的最当长度可以到 3072 Bytes (还有地方说开启 innodb_large_prefix 后的索引长度增大,只针对 row format 是 DYNAMIC 和 COMPRESSED

  2. 对于 Innodb 存储引擎,联合索引的最大长度都是 3072 Bytes

  3. 由于最大长度限制的是字节数,所以不同编码下,索引列的最大长度是不一样的,比如 utf8 编码下,innodb_large_prefix = OFF 时,最大的 varchar 长度是 255,而 utf8mb4 最大的 varchar 长度就是 191

  4. innodb_large_prefix 是 MySQL 5.5 以后引入的,如果想要在开启 innodb_large_prefix 后索引长度能支持到 3072 Bytes,还必须保证 MySQL 的 file format 设置(使用 Barracuda)和 row format 设置 (使用 DYNAMIC 和 COMPRESSED)

  5. 小结一下,innodb_large_prefix=1 并且 innodb_file_format=BARRACUDA 时,对于 row_format 为 dynamic 或 compressed 的表可以指定索引列长度大于 767 bytes。但是索引列总长度的不能大于 3072 bytes的限制仍然存在

MySQL 官方文档的描述:

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

The limits that apply to index key prefixes also apply to full-column index keys.

至于为什么最大限制是 767 Bytes,为什么和 innodb file format 与 row format 有关,有兴趣的可以再研究一下,和 Innodb 的存储结构、表空间、行记录格式等有关。

# 查看数据库的默认编码配置
mysql> show variables like 'char%';

+--------------------------+---------------------------------------------------------------------------+
| Variable_name            | Value                                                                     |
+--------------------------+---------------------------------------------------------------------------+
| character_set_client     | utf8                                                                      |
| character_set_connection | utf8                                                                      |
| character_set_database   | utf8mb4                                                                   |
| character_set_filesystem | binary                                                                    |
| character_set_results    | utf8                                                                      |
| character_set_server     | utf8mb4                                                                   |
| character_set_system     | utf8                                                                      |
| character_sets_dir       | /Users/dfg/workspace/middleware/mysql/mysql-5.7.30-master/share/charsets/ |
+--------------------------+---------------------------------------------------------------------------+
8 rows in set (0.01 sec)

# 查看数据库 test 的编码
mysql> show create database test;
+----------+---------------------------------------------------------------------------------------------+
| Database | Create Database                                                                             |
+----------+---------------------------------------------------------------------------------------------+
| test     | CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */ |
+----------+---------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)


mysql> CREATE TABLE `events_2` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `uniqueId` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
  `type` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  `key1` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

mysql> SET GLOBAL innodb_large_prefix = 0;
Query OK, 0 rows affected, 1 warning (0.00 sec)

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

mysql> alter table events_2 add unique key uni_unique_id (uniqueId);
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

mysql> show create table events_3\G;
*************************** 1. row ***************************
       Table: events_3
Create Table: CREATE TABLE `events_3` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `uniqueId` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
  `type` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
  `key1` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

mysql> alter table events_3 add unique key uni_unique_id (uniqueId);
Query OK, 0 rows affected (0.02 sec)

mysql> show index from events_3;
+----------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table    | Non_unique | Key_name      | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| events_3 |          0 | PRIMARY       |            1 | id          | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
| events_3 |          0 | uni_unique_id |            1 | uniqueId    | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
+----------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

mysql> alter table events_3 character set utf8mb4 collate utf8mb4_unicode_ci;
Query OK, 0 rows affected (0.02 sec)

mysql> show create table events_3\G;
*************************** 1. row ***************************
       Table: events_3
Create Table: CREATE TABLE `events_3` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `uniqueId` varchar(200) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `type` varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `key1` varchar(200) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uni_unique_id` (`uniqueId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

mysql> show variables like 'innodb_file_format';
+--------------------+-----------+
| Variable_name      | Value     |
+--------------------+-----------+
| innodb_file_format | Barracuda |
+--------------------+-----------+
1 row in set (0.16 sec)

mysql> show variables like '%row_format%';
+---------------------------+---------+
| Variable_name             | Value   |
+---------------------------+---------+
| innodb_default_row_format | dynamic |
+---------------------------+---------+

mysql> show variables like 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set (0.26 sec)
CREATE TABLE `events_1` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `uniqueId` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
  `type` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  `key1` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

CREATE TABLE `events_2` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `uniqueId` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
  `type` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  `key1` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

CREATE TABLE `events_3` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `uniqueId` varchar(200) NOT NULL,
  `type` varchar(32) NOT NULL,
  `key1` varchar(200) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


alter table events_1 add unique key uni_unique_id (uniqueId);

show variables like 'innodb_large_prefix';

SET GLOBAL innodb_large_prefix = 0;

参考链接

上一页Request Aborted下一页Java 应用 CPU 100% 排查优化

最后更新于4年前

这有帮助吗?

if innodb_large_prefix is enabled (the default), the index key prefix limit is 3072 bytes for InnoDB tables that use the or row format. If innodb_large_prefix is disabled, the index key prefix limit is 767 bytes for tables of any row format.

The index key prefix length limit is 767 bytes for InnoDB tables that use the or row format.

For example, you might hit this limit with a index of more than 255 characters on a TEXT or VARCHAR column, assuming a utf8mb3 character set and the maximum of 3 bytes for each character.Attempting to use an index key prefix length that exceeds the limit returns an error.

To avoid such errors in replication configurations, avoid enabling innodb_large_prefix on the source if it cannot also be enabled on replicas.If you reduce the InnoDB to 8KB or 4KB by specifying the innodb_page_size option when creating the MySQL instance, the maximum length of the index key is lowered proportionally, based on the limit of 3072 bytes for a 16KB page size. That is, the maximum index key length is 1536 bytes when the page size is 8KB, and 768 bytes when the page size is 4KB.

-- via:

-- via:

DYNAMIC
COMPRESSED
REDUNDANT
COMPACT
column prefix
page size
https://dev.mysql.com/doc/refman/5.7/en/innodb-limits.html
https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_large_prefix
RDS 提示 1071 错误
https://stackoverflow.com/questions/1814532/1071-specified-key-was-too-long-max-key-length-is-767-bytes
https://www.jianshu.com/p/949eeceff3b4