innodb主键的长度为什么不能大于767字节

【Godot】实现对话系统 在 Godot 中实现对话系统(Dialogue System)是游戏开发中的常见需求。Godot本身自带的的灵活性和轻量级脚本语言 GDScript 使得实现对话系统变得相对简单。以下是实现一个基础对话系统的示例。(语言为GDScript但高亮选择Python因为类似)通过 Godot 和 GDScript,我们可以给我们的游戏实现一个对话系统。从简单的文本显示到复杂的分支对话,Godot 提供了足够的灵活性来满足我们的需求。如果需要更高级的功能,可以尝试使用现成的插件如 Dialogic。 阅读详情

一、前言

      这篇文章是基于之前的一篇:导入sql文件报错:1071 Specified key was too long; max key length is 767 bytes ,当时只是知道主键长度不能超过767字节,但是并不知道为什么会这么规定,这个767有什么特殊的含义吗?这篇文章会尽量去解读一下这个767是什么,为什么是它。

二、长度限制767的来源

1、compact行格式溢出

      主键是聚集索引,也是其他二级索引的基础,所以每个主键要在一个数据页存储,不能分布在其他的溢出页,不能像其他大字段一样溢出数据页。

      就是说博主认为,这个主键部分,包括单列索引的部分,它们都是一个整体的,不会像是其他数据文件一样溢出。而对于mysql5.7之前,默认使用的行格式是compact模式。对于这个模式大家可以百度学习下,这里不做详细解答。我们只需要知道这个行格式的溢出设定:当某一列中的数据非常多的话,在数据页中只会存储该列的前767个字节的数据和一个指向其他页的地址,然后把剩下的数据存放到其他页中,这个过程也叫做行溢出,存储超出767字节的那些页面也被称为溢出页。

如图(偷来的图):
在这里插入图片描述

      这个768字节是不是跟767字节很接近了,博主看到这个概念的时候就在想,主键长度就像我们上面说的那样,超过这个阈值就会溢出到地址页,当然,这只是猜想,下面咱们尽量验证下。

2、查询之前报错的数据库,版本是小于5.7的,也就是使用的是compact行格式。

3、按照当时的计算

//这里是由于定义了多个字段共同组成主键索引
(255+10+10)*3 = 825  //在用utf8作为字符集的时候,超过了规定的767 bytes
(255+10+10)*2 = 550  //当该用gbk作为字符集的时候
(255+10+10)*4 = 1100  //当用utf8m4作为字符集的时候,也超标了

      这里的主键长度,后来经过查询mysql手册,并没有明确的说限制它的长度。但是我们发现了另外两个概念:单列索引和索引前缀

4、单列索引和索引前缀

      翻阅诸多资料,大家的一致说法是当单列索引长度大于767的时候,会取前767个字节作为索引前缀,会有个warning但不会直接报错。针对组合索引,比如a,b,c三个字段的组合索引,要求索引长度加起来不能超过3072字节。

767的另一种计算方式:256×3-1

      这个3是字符最大占用空间(utf8)。但是在5.5以后,开始支持4个字节的utf8mb4,因此单纯的767在某些情况下就不是那么通用了,mysql新增一个参数叫做 innodb_large_prefix,可以允许索引达到3072字节。

      这里可以推断,我们一直说的主键长度,其实算是主键索引,而主键索引也是属于单列索引之内的,因为只有一列数据嘛。也就是符合以上mysql对于单列索引长度的限制。

5、为什么主键长度超标会报错,单列索引只是warning呢

      这部分,博主推断是由于主键部分是聚集索引,聚集索引的特性要求它必须是最为高效的结构。按照上面compact行格式的定义,超过阈值之后,主键索引也会分布到其他的页面,这对于主键索引的完整性来说是不可接受的,因此主键长度超标就会报错。而普通的单列索引定义没有主键索引这么严格。

================ 2019/7/26更新 ================================

6、mysql手册证实行格式和索引关键字限制的关系

      在手册中有一句话:记录的值的数据长度是由767个字节的索引关键字限制的限制 COMPACT和REDUNDANT排格式,并为3072个字节DYNAMIC和 COMPRESSED列格式。

链接:https://dev.mysql.com/doc/refman/5.7/en/create-table-secondary-indexes.html

这句话充分验证了我们的猜想,索引前缀的长度限制确实是和行格式有关的。

7、那么行格式的溢出阈值是768字节,为什么索引长度限制是767呢

      本来这个问题博主也是百思不得其解,准备以后再来解答。但是群上有小伙伴对这个也有疑问,那就只能硬着头皮上了。在翻阅compact行格式定义的时候,在手册上发现一句话:

对于每个非NULL可变长度字段,记录头包含一个或两个字节的列长度。如果列的一部分存储在溢出页面的外部,或者最大长度超过255个字节且实际长度超过127个字节,则只需要两个字节。对于外部存储列,2字节长度表示内部存储部分的长度加上指向外部存储部分的20字节指针。内部部分为768字节,因此长度为768 + 20。20字节指针存储列的真实长度。

手册链接: https://dev.mysql.com/doc/refman/5.7/en/innodb-row-format.html

      恍然大悟,如梦初醒。原来还要有1-2个字节要存储列长度,妥妥的。

新解释: 这个768是行格式规定的溢出阈值,对于compact行格式,我们存储一个varchar的列,实际存储数据占用的空间包括:实际数据+真实数据占用字节的长度+null值信息,当规定not null的时候,null值信息不占用空间,那么实际能存储的就是:实际数据 + 真实数据占用字节的长度,这里的真实数据占用字节的长度一般是1-2个字节代表列长度,所以:

767限制 = 768字节 - 1字节的列长度

      也就是说不管是对于什么编码存储,最少是要有一个字节来标识列长度的,所以768-1 = 767,也就是最多会留767字节来存储实际数据,这也是mysql规定索引前缀长度是767的原因。

三、升级mysql5.7之后的长度限制为3072字节

1、mysql5.7的行格式dynamic

      在mysql5.7之后,默认的行格式变成了dynamic行格式,它和compact行格式的大部分特性都相同,只是针对于溢出页的定义是不一样的,如图:

在这里插入图片描述

2、dynamic行格式特点

      对于dynamic行格式而言,假如数据量大导致溢出的话,那么数据页中只会保存一个溢出页的地址,大概是20个字节的指针,而对应的数据都只会存储在溢出页。

      网上查询到的资料是主键长度扩展到了3072字节,经过翻看手册,发现如果innodb_large_prefix启用(默认值),则对于InnoDB使用DYNAMIC 或 COMPRESSED 行格式的表, 索引键前缀限制为3072字节。如果 innodb_large_prefix禁用,则对于任何行格式的表,索引键前缀限制为767字节。

mysql5.7默认的innodb_large_prefix是启用状态,所以对应的索引键前缀是可以设置为3072字节的,我们也可以愉快的设置:varchar(255)了。

3、对3072字节的猜想

      首选我们知道,innodb的每个数据页大小是16KB,也就是16384字节。innodb规定每个数据页至少要有两行记录,而每行记录主要是:行数据+27个字节的额外信息。每个数据页还有页头页尾等信息,总计136字节,所以实际存储数据的N大小为:

				136 + 2*(27+N) < 16384     N=8098字节

      假设在数据量的大小不足以溢出数据页的时候,那么每行的长度至少要小于8098字节,mysql给出的索引长度小于这个值即可。至于为什么要是3072字节,在手册上有这样一句话:

      如果通过在创建MySQL实例时指定选项将InnoDB 页面大小减小到8KB或4KB innodb_page_size,则索引键的最大长度将按比例降低,基于16KB页面大小的3072字节限制。也就是说,当页面大小为8KB时,最大索引密钥长度为1536字节,当页面大小为4KB时,最大索引密钥长度为768字节。

      我们可以理解为是为了当缩小数据页的大小为4KB的时候,我们还可以按照原有的习惯去建索引,而不至于因为索引长度过小,无法正常建索引等。( PS: 这部分也是猜测,后续有新的理解就补充上去)

四、查看当前行格式,修改行格式等

1、查看当前的行格式

mysql> show table status like '表名'\G;
*************************** 1. row ***************************
           Name: 表名
         Engine: InnoDB
        Version: 10
     Row_format: Dynamic   =============就是它
           Rows: 5
 Avg_row_length: 3276
    Data_length: 16384
Max_data_length: 0
   Index_length: 98304
      Data_free: 0
 Auto_increment: 62
    Create_time: 2019-07-11 19:38:50
    Update_time: 2019-07-22 09:59:27
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)

2、新增行格式

CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称

3、修改行格式

ALTER TABLE 表名 ROW_FORMAT=行格式名称

======================================================================

高危预警: 这篇文章,博主经过各种谷歌之后,只是得到了心中的一部分答案。而且并没有较权威的例子来证明这些东西。顶多算是抛砖引玉吧,博主心中的疑惑解开了一些,但是并没有得到充分的验证。希望这篇文章能给你带来一点灵感,如果有什么更好的理解,请务必告诉我,非常感谢,一起学习!

end

Windows 下 Claude Code 使用全记录:从零到一的保姆级图文教程(持续更新) 本文主要介绍了Windows 下 Claude Code 使用全记录:从零到一的保姆级图文教程,希望能对学习使用 Claude Code 的同学们有所帮助。 文章目录 1. 背景 2. 实战教程(2026年最新教程) 2.1 步骤一 Claude Code 环境准备 2.2 步骤二 配置Claude Code 2.3 步骤三 对话 3. 老版本实战教程 3.1 步骤一 配置Node.js 3.2 步骤二 Claude Code配置 3.3 步骤三 配置Claude Code 3.4 步骤四 对话 阅读详情

相关推荐

大象机器人myAGV移动机器人+mechArm六轴机械臂,开源复合机器人开发与实践!

我们这章节的内容是将协作性机械臂打破距离上的限制,跟移动机器人(myAGV)相连接,实现一个案例。

m0_71627844的博客 1488

mysql索引长度超过767bytes问题解决

数据库

yygyj的博客 1446

CP2102 USB 转 UART 模块 PCB 设计项目

不幸的是,我的笔记本电脑只有 USB 端口,所以我需要在 USB 端口和 UART 接口之间进行转换。PCB 布局将足够小,因此我们不一定需要高速布线 USB 线路,但我们将在此将其作为一个简单的示例来实现,以展示如何在这种类型的电路板上实现它。相反,我们只使用屏幕左侧的电路。在这里,我们利用对之间的间距和到 L1 上的铜灌注的距离将差分阻抗设置为目标值。初始布局分为两个部分:USB 连接器和 USB 线路的 TVS 二极管放置在电路板左侧,带有二极管 D4 和 D5 的引脚接头放置在电路板右侧。

jkh920184196的博客 2401

mysql索引长度超过767bytes问题解决。Specified key was too long; max key length is 767 bytes

mysql索引长度超过767bytes问题解决。 错误信息: Specified key was too long; max key length is 767 bytes MySQL的InnoDB存储引擎的表存在一系列的限制条件,其中比较常见的一种是表的字段索引长度限制,该限制与参数innodb_large_prefix相关。 原因分析: 导致上面报错的原因是由于InnoDB表的索引长度限制,在MySQL5.6版本后引入了参数innodb_large_prefix可以解决这个问.

qq_24628659的博客 1万+

Unity地形优化实战:LOD、合批与HLOD打造流畅开放世界

在计算机图形学与游戏开发中,渲染优化是保障应用流畅运行的核心技术。其基本原理在于通过算法与策略,在视觉保真度与硬件资源消耗之间寻求最佳平衡,旨在提升帧率、降低功耗。这一技术的核心价值在于,它直接决定了大规模场景(如开放世界游戏)在性能受限平台(尤其是移动设备)上的可行性。具体到地形渲染这一关键应用场景,开发者需要综合运用多层次细节(LOD)技术来动态调整模型精度,并通过Draw Call合批(Batching)与GPU实例化(GPU Instancing)来大幅减少CPU到GPU的通信开销。对于超大规模世界

weixin_28077113的博客 333

SAE J1850协议:从波形解析到汽车诊断实战

本文深入解析SAE J1850协议在汽车诊断中的应用,重点对比其PWM和VPW两种实现方式的波形特征、帧结构及诊断要点。通过实测案例,详细介绍了如何通过波形分析精准定位通用和福特等美系车型的通信故障,提升汽车电子诊断实战能力。

hill8的博客 965

MySQL 异常:max key length is 767 bytes

最近迁移几张表,又遇到 767 异常,迁移前只检查了 sql_mode 忽略对比了这个参数,导致几张表创建失败,其实解决方法也很简单,开启参数重新导入即可。该 ERROR 常发生在字符串类型的大字段上,本篇文章详细解读该问题。

分享既学习 2142

从仿真到实体:基于Isaac Gym的X20机械狗与Kinova Gen3 Lite机械臂全身协同控制实战

本文详细介绍了基于Isaac Gym仿真平台,实现云深处X20机械狗与Kinova Gen3 Lite机械臂全身协同控制的完整实战流程。内容涵盖环境搭建、模型适配、分阶段训练策略、域随机化技巧,以及最终将训练好的策略安全部署到实体机器人的关键步骤,为复杂机器人系统的仿真到实体迁移提供了宝贵经验。

yhn45678901的博客 489

mysql 内存页解析

大家都知道mysql中数据是存储在物理磁盘上的,而真正的数据处理又是在内存中执行的。由于磁盘的读写速度非常慢,如果每次操作都对磁盘进行频繁读写的话,那么性能一定非常差。为了上述问题,InnoDB将数据划分为若干页,以页作为磁盘与内存交互的基本单位,一般页的大小为16KB。这样的话,一次性至少读取1页数据到内存中或者将1页数据写入磁盘。通过减少内存与磁盘的交互次数,从而提升性能。 页是什么 首先,我们需要知道,页(Pages)是 InnoDB 中管理数据的最小单元。Buffer Pool 中存的就是一

fei33423的专栏 1285

Halcon实战:5种边缘检测算子对比(Sobel、Roberts、Prewitt、Kirsch、Canny)

本文深入对比了Halcon中Sobel、Roberts、Prewitt、Kirsch和Canny五大边缘检测算子的实战表现与核心差异。通过工业图像实例与代码解析,提供了基于噪声水平、边缘连续性及实时性要求的场景化选型指南,帮助工程师精准选择最适合的算子以优化视觉检测流程。

weixin_29266007的博客 392

CDR插件开发之CPG插件004 - 认识VGCore并编译生成你的第一个CPG文件

上篇文章中,讲到了使用VS2019编译CDR类型库 VGCoreAuto.tlb,编译后得到了vgcoreauto.tlh和vgcoreauto.tli两个文件。本文将对这两个文件说明,并演示通过标准的libid形式来导入CDR类型库,在这个过程中,穿插一些VS2019的使用技巧(删除目录、复制工程、打开项目或解决方案、修改解决方案名称、修改项目名称等),使读者循序渐进,逐步提高对VS2019工具的熟练程度,最后通过修改项目属性配置,生成第一个CPG文件。

Zebe 2984

关于MySQL数据库InnoDB存储引擎索引长度限制的tips

有同学问到MySQL数据库InnoDB存储引擎的索引长度问题,简单说几个tips。 关于3072 大家经常碰到InnoDB单列索引长度不能超过767bytes,实际上联合索引还有一个限制是3072。 可以看到,由于每个字段占用255*3, 因此这个索引的大小是3825>3072,报错。 为什么3072 我们知道InnoDB一个page的默认大小是16k。由于是

一寒的博客----我亦无它,唯学习尔! 955

Windows11安装配置openclaw+deepseek(大龙虾)

密码可以随便设置(注意wsl系统本质上是linux系统,设置密码系统是不会像windows一样显示*点位符的),输入密码后敲回车再次输入密码,输入后敲回车。如果不小心关闭这个界面,可以再次进入powershell,输入wsl进行系统。在powershell中输入:curl -fssL https://openclaw.ai/install.sh | bash。下面是否通过第3方平台和openclaw交互,我选择j最后一项:skip for now。到下面这一步,可以通过键盘的左箭头选择Yes.

mahailiang的专栏 344

关于 InnoDB 索引长度限制的 tips

有同学问到InnoDB的索引长度问题,简单说几个tips。 关于3072 大家经常碰到InnoDB单列索引长度不能超过767bytes,实际上联合索引还有一个限制是3072。   可以看到,由于每个字段占用255*3, 因此这个索引的大小是3825>3072,报错。 为什么3072 我们知道InnoDB一个page的默认大小是16k。由于是Btree组织,要求叶

wangsg2014的专栏 2080

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

【MySQL】深入解析767字节索引长度限制:从原理到实战调优

本文深入解析MySQL的767字节索引长度限制,探讨其背后的InnoDB存储引擎原理,并提供三种实战解决方案:启用innodb_large_prefix参数、调整表格式为Dynamic或Compressed、使用前缀索引。文章还分享了生产环境最佳实践,包括版本兼容性考量、性能监控与调优建议,帮助开发者有效应对'Specified key was too long'错误。

weixin_30919571的博客 573

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

mysql 索引长度tips innodb和myisam引擎

由于开发人员对索引认识不深或忽略,还有版本不同等问题,在生产环境中创建表失败,引发了一些问题。归纳了一下     测试环境        mysql> select version(); +------------+ | version()  | +------------+ | 5.5.31-log | +------------+ 1 row in set (0.01 s

aeoluspu的专栏 4153

关于InnoDB索引长度限制的问题

关于3072 大家经常碰到InnoDB单列索引长度不能超过767bytes,实际上联合索引还有一个限制是3072。 Sql代码链接地址 mysql>CREATETABLE`tb`( ->`a`varchar(255)DEFAULTNULL, ->`b`varchar(255)DEFAULT...

weixin_31040783的博客 1163

mysql联合主键有长度限制吗_mysql使用联合索引提示字符长度超限制解决办法

​mysql在创建数据库的时候,字符集设置的不是utf8而是utf9mb4,在导入sql脚本的时候,发现提示如下错误:​从上图中,我们可以看出,使用的是innodb及字符集。错误提示是长度太长了:Specified key was too long; max key length is 767 bytes来查看下创建表的语句:CREATE TABLE `xxl_job_registry` (`id...

weixin_32787485的博客 1517

1071 - Specified key was too long; max key length is 767 bytes

今天优化公司项目时候创建索引时报了: 1071 - Specified key was too long; max key length is 767 bytes错误,意思就是“索引字段长度太长,超过了767bytes”。 查了一下 mysql的varchar主键只支持不超过767个字节或者768/2=384个双字节 或者767/3=255个三字节的字段 而GBK是双字节的,UTF8是三字节的。 innodb存储引擎,多列索引的长度限制如下: 每个列的长度不能大于767 bytes;所有组成索引列的长度和

qq_38925911的博客 1万+

【MySql】Specified key was too long; max key length is 767 bytes的解决方案

问题背景 今天由于业务需要,在mysql5.6的数据库上,创建了一个主键是varchar(500)的字段,然后就提示这样的错 Specified key was too long; max key length is 767 bytes 原来是主键的长度太长,最大长度仅支持767字节,注意,这里的是字节。 那么,我定义一个主键是varchar(500)的字段,不管我使用utf8编码,那...

阳阳的博客 1万+

mysql innodb 索引 多大合适_mysql InnoDB引擎索引超过长度限制

组合索引长度之和大于 767 bytes并无影响,当有某个字段定义长度大于 767 bytes(1000*3)时,仅产生告警,但不影响创建,超长字段会取前 255 字符作为前缀索引,并且组合索引中字段出现的顺序并无关系。为什么3072InnoDB一个page的默认大小是 16 k。由于是Btree组织,要求叶子节点上一个page至少包含两条记录(否则就退化链表了)。所以一个记录最多不能超过 8 k...

weixin_32016817的博客 662

mysql InnoDB引擎索引超过长度限制

组合索引长度之和大于 767 bytes并无影响,当有某个字段定义长度大于 767 bytes(1000*3)时,仅产生告警,但不影响创建,超长字段会取前 255 字符作为前缀索引,并且组合索引中字段出现的顺序并无关系。为什么3072InnoDB一个page的默认大小是 16 k。由于是Btree组织,要求叶子节点上一个page至少包含两条记录(否则就退化链表了)。所以一个记录最多不能超过 8 k...

weixin_39372979的博客 4772

mysql报错Specified key was too long; max key length is 767 bytes

innodb_large_prefix参数是用来指定InnoDB存储引擎中最大索引长度的参数。在MySQL 5.6.14版本之后,这个参数默认值是OFF,也就是关闭状态。当开启innodb_large_prefix参数时,InnoDB存储引擎支持的索引长度将从767字节扩展到3072字节,这可以更好地支持更长的索引键。varchar类型是字符,同时使用的字符集为(utf8mb4),这个指每个字符最大的字节数为4,所以很明显 4*72 < 767。2、修改:innodb_large_prefix。

guanqun007的博客 1359

MySQL InnoDB引擎索引长度受限怎么办?

大家应该知道InnoDB单列索引长度不能超过767bytes,联合索引还有一个限制是长度不能超过3072。 mysql> CREATE TABLE `tb` (      ->   `a` varchar(255) DEFAULT NULL,      ->   `b` varchar(255) DEFAULT NULL,      ->   `c` varchar(255) DEFAULT

老屈长谈 2万+

mysql索引的最大字节3072_MySQL中索引的长度的限制

参考:http://dinglin.iteye.com/blog/1681332单列索引的长度的限制(5.6里面默认不能超过767bytes,5.7不超过3072bytes):起因是256×3-1=767。这个3是字符最大占用空间(utf8)。但是在5.5以后,开始支持4个字节的uutf8。255×4>767, 于是增加了一个参数叫做 innodb_large_prefix# 256的由来...

weixin_36430300的博客 3793

mysql主键设置长度_MYSQLl数据库主键设置长度控制

MYSQLl数据库主键设置长度控制1、出现的问题?JEECMS套件(jeecms-2012-sp1)中有一个jeecms-db-2012-sp1.sql文件,文件里面有一张“jc_file”的表,表里面有一个字段“file_path”的长度是255,在安装此套件的过程中会报错,具体错误如下:Query : CREATE TABLE `jc_file` ( `file_path` varchar...

weixin_39834084的博客 1786
上一篇: mysql的查询需要遍历几次B+树,理论上需要几次磁盘I/O?
下一篇: 通过IP获取地址,限制某些地址访问(GeoIp)
铁柱同学
铁柱同学 优质创作者: 后端开发技术领域 优质创作者: 后端开发技术领域 领域专家: 前端开发技术领域 领域专家: 前端开发技术领域
博客等级 码龄10年 1万+粉丝 430原创
评论 10
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铁柱同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值